'use strict';

/*-------------------------------------------------------------
       _                         
 _   _(_) __ _ _ __ _____      __
| | | | |/ _` | '__/ _ \ \ /\ / /
| |_| | | (_| | | | (_) \ V  V / 
\__ , |_|\__, |_|  \___/ \_/\_/  
 |___/   |___/ (C)2023 shhoo.cn

 1、查询可入网设备
 2、设置入网设备名称及路数
-------------------------------------------------------------*/
import moment from 'moment';
moment.locale('zh-cn');
import Curd from '../func/curd'
import { RedisGatewayClass } from "../lib/redis_gateway";
import Mysql from "../lib/mysqlUtil";
import { LoRaComCtrlClass } from "./loRaComCtrl"
import { TcpComCtrlClass } from "../device/tcpComCtrl"
import { WriteTimerCoils } from "../device/loRaModbusTcp"
var ROLLER_CTRL_INTERVAL = {};
var ROLLER_CTRL_CLOCK = {};
var RollerCtrlTimeout = {};
var ClearRollerIntervalFlag = {};
interface mergeRollerForceStopParamsObj {
      addr: string[],//lora地址
      sn: string[],//sn
      zoneId: number[],//区域ID
      channel: number[],//通道
      alias: string[],//名称
      mode_driver: string[],//设备驱动
      lastOpen: number[],//上次开度
      openChNum: number[],//开启通道
      closeChNum: number[],//关闭通道

}
function mergeRollerGroupStop(RedisGateway: RedisGatewayClass, LoRaComCtrl: LoRaComCtrlClass, TcpComCtrl: TcpComCtrlClass, rollersInfo: any[]) {
      //{"openChName":"DO_E240100B_0_2","openTravel":[10,10,10,10,10,10,10,10,10,10],"forceOpenTime":120,"openCorrection":0,"closeChName":"DO_E240100B_0_4","closeTravel":[10,10,10,10,10,10,10,10,10,10],"forceCloseTime":110,"closeCorrection":0,"errCorrectionCnt":0}
      // console.log(slaverInfo.f_pre_allocate3);
      // console.log(rollersInfo)
      let mergeForceStopParams: mergeRollerForceStopParamsObj = {
            addr: [],
            sn: [],
            zoneId: [],
            channel: [],
            alias: [],
            mode_driver: [],//设备驱动
            lastOpen: [],//上次开度
            openChNum: [],//开启通道
            closeChNum: [],//关闭通道
      };
      let cntMerge = 0;
      rollersInfo.forEach(slaverInfo => {
            let lastOpen = parseInt(slaverInfo.f_last_value);
            lastOpen = isNaN(lastOpen) ? 0 : lastOpen;
            let sn = slaverInfo.f_actuator_sn;
            let addr = slaverInfo.f_actuator_addr;
            let f_channel = parseInt(slaverInfo.f_channel);
            let f_zone_id = parseInt(slaverInfo.f_zone_id);
            let f_actuator_alias = slaverInfo.f_actuator_alias;
            let settings = JSON.parse(slaverInfo.f_pre_allocate3);
            let openChName = settings.openChName;
            let closeChName = settings.closeChName;

            Curd.QueryTwoNewActuatorsInfo(openChName, closeChName).then((DOInfos) => {
                  // console.log(DOInfos)
                  if (DOInfos) {
                        let mode_driver = DOInfos[0].mode_driver;
                        let groupId = DOInfos[0].groupId;
                        let openChInfo = DOInfos.find((element) => {
                              return element.name == openChName;
                        })
                        let closeChInfo = DOInfos.find((element) => {
                              return element.name == closeChName;
                        })
                        if (openChInfo != undefined && closeChInfo != undefined) {
                              mergeForceStopParams.addr.push(addr);
                              mergeForceStopParams.sn.push(sn);
                              mergeForceStopParams.zoneId.push(f_zone_id);
                              mergeForceStopParams.channel.push(f_channel);
                              mergeForceStopParams.alias.push(f_actuator_alias);
                              mergeForceStopParams.mode_driver.push(mode_driver);
                              mergeForceStopParams.lastOpen.push(lastOpen);//上次开度
                              mergeForceStopParams.openChNum.push(openChInfo.channel);//开启通道
                              mergeForceStopParams.closeChNum.push(closeChInfo.channel);//关闭通道
                        }
                        if (cntMerge == rollersInfo.length - 1) {
                              if (mergeForceStopParams.mode_driver[0] == 'LoRa_ComCtrl') {
                                    LoRaComCtrl.WriteTimerCoils(addr, groupId, mergeForceStopParams.openChNum.concat(mergeForceStopParams.closeChNum), new Array(mergeForceStopParams.openChNum.length + mergeForceStopParams.closeChNum.length).fill(0), 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                          if (null == err) {
                                                for (let i = 0; i < mergeForceStopParams.addr.length; i++) {
                                                      if (ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`] != null) {
                                                            clearInterval(ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`]);
                                                            ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`] = null;
                                                      }
                                                      if (RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`] != null) {
                                                            clearInterval(RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`]);
                                                            RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`] = null;
                                                      }
                                                      let para = {
                                                            f_actuator_sn: mergeForceStopParams.sn[i],
                                                            f_actuator_addr: mergeForceStopParams.addr[i],
                                                            f_channel: mergeForceStopParams.channel[i],
                                                            staId: 8,
                                                            f_zone_id: mergeForceStopParams.zoneId[i],
                                                            f_actuator_alias: mergeForceStopParams.alias[i],
                                                      }
                                                      ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeForceStopParams.sn[i]}`] = 10;
                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 8, mergeForceStopParams.lastOpen[i]);
                                                      ROLLER_CTRL_CLOCK[`${mergeForceStopParams.sn[i]}`] = false;
                                                }
                                          }
                                    })
                              } else if (mergeForceStopParams.mode_driver[0] == 'Tcp_ComCtrl') {
                                    TcpComCtrl.WriteTimerCoils(addr, groupId, mergeForceStopParams.openChNum.concat(mergeForceStopParams.closeChNum), new Array(mergeForceStopParams.openChNum.length + mergeForceStopParams.closeChNum.length).fill(0), 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                          if (null == err) {
                                                for (let i = 0; i < mergeForceStopParams.addr.length; i++) {
                                                      if (ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`] != null) {
                                                            clearInterval(ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`]);
                                                            ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`] = null;
                                                      }
                                                      if (RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`] != null) {
                                                            clearInterval(RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`]);
                                                            RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`] = null;
                                                      }
                                                      let para = {
                                                            f_actuator_sn: mergeForceStopParams.sn[i],
                                                            f_actuator_addr: mergeForceStopParams.addr[i],
                                                            f_channel: mergeForceStopParams.channel[i],
                                                            staId: 8,
                                                            f_zone_id: mergeForceStopParams.zoneId[i],
                                                            f_actuator_alias: mergeForceStopParams.alias[i],
                                                      }
                                                      ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeForceStopParams.sn[i]}`] = 10;
                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 8, mergeForceStopParams.lastOpen[i]);
                                                      ROLLER_CTRL_CLOCK[`${mergeForceStopParams.sn[i]}`] = false;
                                                }
                                          }
                                    })
                              } else if (mergeForceStopParams.mode_driver[0] == 'LORA_MODBUSTCP') {
                                    WriteTimerCoils(addr, groupId, mergeForceStopParams.openChNum.concat(mergeForceStopParams.closeChNum), new Array(mergeForceStopParams.openChNum.length + mergeForceStopParams.closeChNum.length).fill(0), 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                          if (null == err) {
                                                for (let i = 0; i < mergeForceStopParams.addr.length; i++) {
                                                      if (ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`] != null) {
                                                            clearInterval(ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`]);
                                                            ROLLER_CTRL_INTERVAL[`${mergeForceStopParams.sn[i]}`] = null;
                                                      }
                                                      if (RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`] != null) {
                                                            clearInterval(RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`]);
                                                            RollerCtrlTimeout[`${mergeForceStopParams.sn[i]}`] = null;
                                                      }
                                                      let para = {
                                                            f_actuator_sn: mergeForceStopParams.sn[i],
                                                            f_actuator_addr: mergeForceStopParams.addr[i],
                                                            f_channel: mergeForceStopParams.channel[i],
                                                            staId: 8,
                                                            f_zone_id: mergeForceStopParams.zoneId[i],
                                                            f_actuator_alias: mergeForceStopParams.alias[i],
                                                      }
                                                      ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeForceStopParams.sn[i]}`] = 10;
                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 8, mergeForceStopParams.lastOpen[i]);
                                                      ROLLER_CTRL_CLOCK[`${mergeForceStopParams.sn[i]}`] = false;
                                                }
                                          }
                                    })
                              }
                        } else {
                              cntMerge++;
                        }
                  }

            }).catch((err) => {

            })

      });

}
interface mergeRollerCtrlParamsObj {
      addr: string[],//lora地址
      sn: string[],//sn
      zoneId: number[],//区域ID
      channel: number[],//通道
      alias: string[],//名称
      mode_driver: string[],//设备驱动
      lastOpen: number[],//上次开度
      targetOpen: number[],//目标开度
      openChNum: number[],//开启通道
      closeChNum: number[],//关闭通道
      openTimeSec: number[],//开启时长
      closeTimeSec: number[],//关闭时长
      forceCtrlCaculateTimeSec: number[],//强制全开全关时用于计算实时开度的时间
      timeOut: number[],//结束等待时间
      isCorrection: boolean[],//是否校正开度
      correctionTimeOut: number[],//校正等待时间
      correctionOpenTimeSec: number[],//校正开启时间
      correctionCloseTimeSec: number[],//校正关闭时间
      beginStatusId: number[],//开始工作时的状态ID
      isForceOpen: boolean[],
      settings: any[]//f_pre_allocate3中卷膜控制器设定参数
}
function mergeRollerGroupCtrl(RedisGateway: RedisGatewayClass, LoRaComCtrl: LoRaComCtrlClass, TcpComCtrl: TcpComCtrlClass, rollersInfo: any[], targetOpen: number, isCorrection: boolean) {
      //{"openChName":"DO_E240100B_0_2","openTravel":[10,10,10,10,10,10,10,10,10,10],"forceOpenTime":120,"openCorrection":0,"closeChName":"DO_E240100B_0_4","closeTravel":[10,10,10,10,10,10,10,10,10,10],"forceCloseTime":110,"closeCorrection":0,"errCorrectionCnt":0}
      // console.log(slaverInfo.f_pre_allocate3);
      let mergeCtrlParams: mergeRollerCtrlParamsObj = {
            addr: [],
            sn: [],
            zoneId: [],
            channel: [],
            alias: [],
            mode_driver: [],//设备驱动
            lastOpen: [],//上次开度
            targetOpen: [],//目标开度
            openChNum: [],//开启通道
            closeChNum: [],//关闭通道
            openTimeSec: [],//开启时长
            forceCtrlCaculateTimeSec: [],//强制全开全关时用于计算实时开度的时间
            closeTimeSec: [],//关闭时长
            timeOut: [],//结束等待时间
            isCorrection: [],//是否校正开度
            correctionTimeOut: [],//校正等待时间
            correctionOpenTimeSec: [],//校正开启时间
            correctionCloseTimeSec: [],//校正关闭时间
            beginStatusId: [],//开始工作时的状态ID
            isForceOpen: [],//100%是否强制全开
            settings: []
      };
      let cntMerge = 0;
      rollersInfo.forEach(slaverInfo => {
            let lastOpen = parseInt(slaverInfo.f_last_value);
            lastOpen = isNaN(lastOpen) ? 0 : lastOpen;
            let sn = slaverInfo.f_actuator_sn;
            let addr = slaverInfo.f_actuator_addr;
            let f_channel = parseInt(slaverInfo.f_channel);
            let f_zone_id = parseInt(slaverInfo.f_zone_id);
            let f_actuator_alias = slaverInfo.f_actuator_alias;
            let settings = JSON.parse(slaverInfo.f_pre_allocate3);
            let openChName = settings.openChName;
            let openTravel = settings.openTravel;
            let isForceOpen = settings.isForceOpen ? settings.isForceOpen : false;
            let forceOpenTime = settings.forceOpenTime;
            let openCorrection = settings.openCorrection;
            let closeChName = settings.closeChName;
            let closeTravel = settings.closeTravel;
            let forceCloseTime = settings.forceCloseTime;
            let closeCorrection = settings.closeCorrection;
            let scrapTimeSec = settings.scrapTimeSec;
            let openChOpenTimeSec = 0;//开启通道的打开时长
            let closeChOpenTimeSec = 0;//关闭通道打开时长
            let forceCtrlCaculateTimeSec = forceOpenTime;
            let timeOut = 0;

            Curd.QueryTwoNewActuatorsInfo(openChName, closeChName).then((DOInfos) => {
                  // console.log(DOInfos)
                  if (DOInfos) {
                        if (targetOpen == 240 || targetOpen == 0) {//强制全关
                              if (lastOpen == 0 && targetOpen == 0) {
                                    // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】=======已经全关了=======`)
                                    openChOpenTimeSec = 0;
                                    closeChOpenTimeSec = 0;
                                    timeOut = 0;
                              } else {
                                    openChOpenTimeSec = 0;
                                    closeChOpenTimeSec = forceCloseTime;
                                    forceCtrlCaculateTimeSec = calculateCloseTravelTime(lastOpen, closeTravel, targetOpen, closeCorrection);
                                    timeOut = forceCloseTime;
                              }
                        } else if (targetOpen == 241 || (targetOpen == 100 && isForceOpen == true)) {//强制全开
                              isForceOpen = true;//区分100和强制
                              closeChOpenTimeSec = 0;
                              openChOpenTimeSec = forceOpenTime;
                              forceCtrlCaculateTimeSec = calculateOpenTravelTime(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec);
                              timeOut = forceOpenTime;
                        } else if (lastOpen == targetOpen) {
                              openChOpenTimeSec = 0;
                              closeChOpenTimeSec = 0;
                              timeOut = 0;
                        } else {
                              if (lastOpen > targetOpen) {//上次开度大于设定开度,关棚计算,不计算搭边时间
                                    openChOpenTimeSec = 0;
                                    closeChOpenTimeSec = calculateCloseTravelTime(lastOpen, closeTravel, targetOpen, closeCorrection);
                                    timeOut = closeChOpenTimeSec;
                              } else {//开棚计算,需要判断上次开度是否为0，为零需要加上搭边时间
                                    openChOpenTimeSec = calculateOpenTravelTime(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec);
                                    closeChOpenTimeSec = 0;
                                    timeOut = openChOpenTimeSec;
                              }
                        }
                        let mode_driver = DOInfos[0].mode_driver;
                        let groupId = DOInfos[0].groupId;
                        let openChInfo = DOInfos.find((element) => {
                              return element.name == openChName;
                        })
                        let closeChInfo = DOInfos.find((element) => {
                              return element.name == closeChName;
                        })
                        // console.log(JSON.stringify(settings))
                        updateRollerSettings(sn, JSON.stringify(settings));
                        if (openChInfo != undefined && closeChInfo != undefined) {
                              if (ROLLER_CTRL_CLOCK[`${sn}`] != true) {
                                    if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                          clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                          ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                    }
                                    if (RollerCtrlTimeout[`${sn}`] != null) {
                                          clearInterval(RollerCtrlTimeout[`${sn}`]);
                                          RollerCtrlTimeout[`${sn}`] = null;
                                    }
                                    console.log(`============== ${`${sn}`},${ROLLER_CTRL_CLOCK[`${sn}`]}==========`)
                                    ROLLER_CTRL_CLOCK[`${sn}`] = true;
                                    console.log(`============== ${`${sn}`},${ROLLER_CTRL_CLOCK[`${sn}`]}==========`)
                                    if (!isCorrection) {//无需校准
                                          mergeCtrlParams.addr.push(addr);
                                          mergeCtrlParams.sn.push(sn);
                                          mergeCtrlParams.zoneId.push(f_zone_id);
                                          mergeCtrlParams.channel.push(f_channel);
                                          mergeCtrlParams.alias.push(f_actuator_alias);
                                          mergeCtrlParams.mode_driver.push(mode_driver);
                                          mergeCtrlParams.lastOpen.push(lastOpen);//上次开度
                                          mergeCtrlParams.targetOpen.push(targetOpen == 240 ? 0 : targetOpen == 241 ? 100 : targetOpen);//目标开度
                                          mergeCtrlParams.openChNum.push(openChInfo?.channel);//开启通道
                                          mergeCtrlParams.closeChNum.push(closeChInfo?.channel);//关闭通道
                                          mergeCtrlParams.openTimeSec.push(openChOpenTimeSec);//开启时长
                                          mergeCtrlParams.forceCtrlCaculateTimeSec.push(forceCtrlCaculateTimeSec);//开启时长
                                          mergeCtrlParams.closeTimeSec.push(closeChOpenTimeSec);//关闭时长
                                          mergeCtrlParams.isCorrection.push(false);//是否校正开度
                                          mergeCtrlParams.timeOut.push(timeOut);
                                          mergeCtrlParams.correctionTimeOut.push(0);//校正等待时间
                                          mergeCtrlParams.correctionOpenTimeSec.push(0);//校正开启时间
                                          mergeCtrlParams.correctionCloseTimeSec.push(0);//校正关闭时间
                                          mergeCtrlParams.beginStatusId.push(((targetOpen == 100 && isForceOpen == true) || targetOpen == 241 || targetOpen == 0) ? 2 : 4);//开始工作时的状态ID
                                          mergeCtrlParams.isForceOpen.push(isForceOpen);
                                          mergeCtrlParams.settings.push(settings);

                                    } else {
                                          // console.log(0, openTravel, targetOpen, settings.openCorrection, settings.scrapTimeSe)
                                          let correctionOpenTimeSec = calculateOpenTravelTime(0, openTravel, targetOpen, settings.openCorrection, settings.scrapTimeSec);//校正开启时间
                                          mergeCtrlParams.addr.push(addr);
                                          mergeCtrlParams.sn.push(sn);
                                          mergeCtrlParams.zoneId.push(f_zone_id);
                                          mergeCtrlParams.channel.push(f_channel);
                                          mergeCtrlParams.alias.push(f_actuator_alias);
                                          mergeCtrlParams.mode_driver.push(mode_driver);
                                          mergeCtrlParams.lastOpen.push(lastOpen);//上次开度
                                          mergeCtrlParams.targetOpen.push(targetOpen == 240 ? 0 : targetOpen == 241 ? 100 : targetOpen);//目标开度
                                          mergeCtrlParams.openChNum.push(openChInfo?.channel);//开启通道
                                          mergeCtrlParams.closeChNum.push(closeChInfo?.channel);//关闭通道
                                          mergeCtrlParams.openTimeSec.push(0);//开启时长
                                          mergeCtrlParams.timeOut.push(forceCloseTime);
                                          mergeCtrlParams.closeTimeSec.push(forceCloseTime);//关闭时长
                                          mergeCtrlParams.forceCtrlCaculateTimeSec.push(forceCtrlCaculateTimeSec);//开启时长
                                          mergeCtrlParams.isCorrection.push(true);//是否校正开度
                                          mergeCtrlParams.correctionTimeOut.push(correctionOpenTimeSec);//校正等待时间
                                          mergeCtrlParams.correctionOpenTimeSec.push(correctionOpenTimeSec);
                                          mergeCtrlParams.correctionCloseTimeSec.push(0);//校正关闭时间
                                          mergeCtrlParams.beginStatusId.push(16);//开始工作时的状态ID
                                          mergeCtrlParams.isForceOpen.push(isForceOpen);
                                          mergeCtrlParams.settings.push(settings);

                                    }
                              } else {
                                    console.log(`${f_actuator_alias}控制锁定中，不可控制，等待解锁或强制停止解锁`)
                              }
                        }
                        //自动校准回0
                        if (cntMerge == rollersInfo.length - 1) {
                              console.log(mergeCtrlParams)
                              if (mergeCtrlParams.addr.length > 0) {
                                    let mergeCtrlInfo = mergeCtrlParams;
                                    switch (mergeCtrlInfo.mode_driver[0]) {
                                          case "LoRa_ComCtrl":
                                                // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtr>】LoRa_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                LoRaComCtrl.WriteTimerCoils(addr, groupId, mergeCtrlInfo.openChNum.concat(mergeCtrlInfo.closeChNum), mergeCtrlInfo.openTimeSec.concat(mergeCtrlInfo.closeTimeSec), 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                      if (null == err) {
                                                            for (let i = 0; i < mergeCtrlInfo.addr.length; i++) {
                                                                  let para = {
                                                                        f_actuator_sn: mergeCtrlInfo.sn[i],
                                                                        f_actuator_addr: mergeCtrlInfo.addr[i],
                                                                        f_channel: mergeCtrlInfo.channel[i],
                                                                        staId: mergeCtrlInfo.beginStatusId[i],
                                                                        f_zone_id: mergeCtrlInfo.zoneId[i],
                                                                        f_actuator_alias: mergeCtrlInfo.alias[i],
                                                                  }
                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;

                                                                  /**
                                                                   * 需要回校正
                                                                   * 1、等待回0，关闭关行程时间
                                                                   * 2、时间到后开启
                                                                   */
                                                                  if (mergeCtrlInfo.isCorrection[i] == true) {//
                                                                        // console.log(para)
                                                                        setTimeout(() => {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, mergeCtrlInfo.lastOpen[i]);
                                                                        }, i * 100);
                                                                        let timeOutCnt = 0;
                                                                        let realtimeOpen = 2;
                                                                        let remainingTime = 0;//计算已工作时长
                                                                        ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                              if (timeOutCnt < (mergeCtrlInfo.timeOut[i] + 2 * (i - 1)) / 2) {
                                                                                    timeOutCnt++;
                                                                                    ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] += 1;
                                                                                    remainingTime += 1;
                                                                                    realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - 0) / mergeCtrlInfo.timeOut[i]));
                                                                                    realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                    // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[校正回零]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - 0)/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                    ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, realtimeOpen);
                                                                              } else {
                                                                                    console.log(`@@@@@@@@@@@@@@@@@====校正归零完成=====@@@@@@@@@@@@@@@@@@`)
                                                                                    clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                    ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                              }
                                                                        }, 2000)
                                                                        RollerCtrlTimeout[`${mergeCtrlInfo.sn[i]}`] = setTimeout(() => {
                                                                              mergeCtrlInfo.lastOpen[i] = 0;
                                                                              RollerCtrlTimeout[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, 0);
                                                                              ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              let realtimeOpen = 2;
                                                                              mergeCtrlInfo.settings[i].errCorrectionCnt = 0;
                                                                              updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                              ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              LoRaComCtrl.WriteTimerCoils(addr, groupId, [mergeCtrlInfo.openChNum[i], mergeCtrlInfo.closeChNum[i]], [mergeCtrlInfo.correctionOpenTimeSec[i], mergeCtrlInfo.correctionCloseTimeSec[i]], 300 + Math.random() * 300, 3, true, function (err: string | null, data1: any | null) {
                                                                                    if (null == err) {
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                          let remainingTime = mergeCtrlInfo.correctionTimeOut[i] - Math.max(...data1.openTimeSecArr);//计算已工作时长
                                                                                          console.log(`Index:${i}, Channel:${mergeCtrlInfo.channel[i]},TimeOut:${mergeCtrlInfo.correctionTimeOut[i]},RcvTimeOut:${Math.max(...data1.openTimeSecArr)},remainingTime:${remainingTime},======================`)
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                                if (ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] == true) {
                                                                                                      ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                                      clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                                      ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                                      ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                                } else {
                                                                                                      remainingTime += 1;
                                                                                                      if (mergeCtrlInfo.targetOpen[i] > realtimeOpen) {//开棚 上次开度
                                                                                                            realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.correctionTimeOut[i]));
                                                                                                            realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.targetOpen[i]} - ${mergeCtrlInfo.lastOpen[i]})/ ${mergeCtrlInfo.correctionTimeOut[i]}=${realtimeOpen}`,)
                                                                                                      } else {
                                                                                                            ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                            realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                                      }
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                                }
                                                                                          }, 1000)
                                                                                    } else {
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                    }
                                                                              })
                                                                        }, (mergeCtrlInfo.timeOut[i] + 2 * (i + 3)) * 1000);
                                                                  } else {//不用校正
                                                                        console.log(mergeCtrlInfo.targetOpen[i])
                                                                        if ((mergeCtrlInfo.targetOpen[i] == 100 && mergeCtrlInfo.isForceOpen[i] == true) || mergeCtrlInfo.targetOpen[i] == 241 || mergeCtrlInfo.targetOpen[i] == 240 || mergeCtrlInfo.targetOpen[i] == 0) {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, mergeCtrlInfo.lastOpen[i]);
                                                                              mergeCtrlInfo.settings[i].errCorrectionCnt = mergeCtrlInfo.settings[i].errCorrectionNumber;
                                                                              updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                              let timeOutCnt = 0;
                                                                              let realtimeOpen = 2;
                                                                              let remainingTime = mergeCtrlInfo.timeOut[i] - Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]]);//计算已工作时长
                                                                              ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                    if (timeOutCnt < mergeCtrlInfo.timeOut[i] / 2) {
                                                                                          timeOutCnt++;
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] += 1;
                                                                                          // ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, mergeCtrlInfo.lastOpen[i]);

                                                                                          remainingTime += 2;
                                                                                          if (mergeCtrlInfo.targetOpen[i] > mergeCtrlInfo.lastOpen[i]) {//开棚 上次开度
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.forceCtrlCaculateTimeSec[i]));
                                                                                                realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[强制卷膜]计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.forceCtrlCaculateTimeSec[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen >= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else if (mergeCtrlInfo.targetOpen[i] < mergeCtrlInfo.lastOpen[i]) {
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - mergeCtrlInfo.targetOpen[i]) / mergeCtrlInfo.forceCtrlCaculateTimeSec[i]));
                                                                                                realtimeOpen = realtimeOpen < mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[强制卷膜]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.forceCtrlCaculateTimeSec[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else {
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                          }
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, realtimeOpen);
                                                                                    } else {
                                                                                          console.log(`@@@@@@@@@@@@@@@@@强制卷膜完成@@@@@@@@@@@@@@@@@@`)
                                                                                          mergeCtrlInfo.settings[i].errCorrectionCnt = 0;
                                                                                          updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                    }

                                                                              }, 2000)
                                                                        } else {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, mergeCtrlInfo.lastOpen[i]);
                                                                              let remainingTime = mergeCtrlInfo.timeOut[i] - Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]]);//计算已工作时长
                                                                              console.log(`Index:${i}, Channel:${mergeCtrlInfo.channel[i]},TimeOut:${mergeCtrlInfo.timeOut[i]},RcvTimeOut:${Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]])},remainingTime:${remainingTime}======================`)
                                                                              ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              let realtimeOpen = 2;
                                                                              ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                    if (ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] == true) {
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                    } else {
                                                                                          remainingTime += 1;
                                                                                          if (mergeCtrlInfo.targetOpen[i] > mergeCtrlInfo.lastOpen[i]) {//开棚 上次开度
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.timeOut[i]));
                                                                                                realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[中间开度]计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen >= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else if (mergeCtrlInfo.targetOpen[i] < mergeCtrlInfo.lastOpen[i]) {
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - mergeCtrlInfo.targetOpen[i]) / mergeCtrlInfo.timeOut[i]));
                                                                                                realtimeOpen = realtimeOpen < mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[中间开度]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else {
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                          }
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                    }
                                                                              }, 1000)
                                                                        }
                                                                  }

                                                            }

                                                      } else {
                                                            console.log(err)
                                                            for (let i = 0; i < mergeCtrlInfo.addr.length; i++) {
                                                                  ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                            }
                                                            RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                      }

                                                })
                                                break;
                                          case "Tcp_ComCtrl":
                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtr>】Tcp_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                TcpComCtrl.WriteTimerCoils(addr, groupId, mergeCtrlInfo.openChNum.concat(mergeCtrlInfo.closeChNum), mergeCtrlInfo.openTimeSec.concat(mergeCtrlInfo.closeTimeSec), 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                      if (null == err) {
                                                            for (let i = 0; i < mergeCtrlInfo.addr.length; i++) {
                                                                  let para = {
                                                                        f_actuator_sn: mergeCtrlInfo.sn[i],
                                                                        f_actuator_addr: mergeCtrlInfo.addr[i],
                                                                        f_channel: mergeCtrlInfo.channel[i],
                                                                        staId: mergeCtrlInfo.beginStatusId[i],
                                                                        f_zone_id: mergeCtrlInfo.zoneId[i],
                                                                        f_actuator_alias: mergeCtrlInfo.alias[i],
                                                                  }
                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;

                                                                  /**
                                                                   * 需要回校正
                                                                   * 1、等待回0，关闭关行程时间
                                                                   * 2、时间到后开启
                                                                   */
                                                                  if (mergeCtrlInfo.isCorrection[i] == true) {//
                                                                        // console.log(para)
                                                                        setTimeout(() => {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, mergeCtrlInfo.lastOpen[i]);
                                                                        }, i * 100);
                                                                        let timeOutCnt = 0;
                                                                        let realtimeOpen = 2;
                                                                        let remainingTime = 0;//计算已工作时长
                                                                        ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                              if (timeOutCnt < (mergeCtrlInfo.timeOut[i] + 2 * (i - 1)) / 2) {
                                                                                    timeOutCnt++;
                                                                                    ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] += 1;
                                                                                    remainingTime += 1;
                                                                                    realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - 0) / mergeCtrlInfo.timeOut[i]));
                                                                                    realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                    // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[校正回零]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - 0)/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                    ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, realtimeOpen);
                                                                              } else {
                                                                                    console.log(`@@@@@@@@@@@@@@@@@====校正归零完成=====@@@@@@@@@@@@@@@@@@`)
                                                                                    clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                    ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                              }
                                                                        }, 2000)
                                                                        RollerCtrlTimeout[`${mergeCtrlInfo.sn[i]}`] = setTimeout(() => {
                                                                              mergeCtrlInfo.lastOpen[i] = 0;
                                                                              RollerCtrlTimeout[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, 0);
                                                                              ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              let realtimeOpen = 2;
                                                                              mergeCtrlInfo.settings[i].errCorrectionCnt = 0;
                                                                              updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                              ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              TcpComCtrl.WriteTimerCoils(addr, groupId, [mergeCtrlInfo.openChNum[i], mergeCtrlInfo.closeChNum[i]], [mergeCtrlInfo.correctionOpenTimeSec[i], mergeCtrlInfo.correctionCloseTimeSec[i]], 300 + Math.random() * 300, 3, true, function (err: string | null, data1: any | null) {
                                                                                    if (null == err) {
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                          let remainingTime = mergeCtrlInfo.correctionTimeOut[i] - Math.max(...data1.openTimeSecArr);//计算已工作时长
                                                                                          console.log(`Index:${i}, Channel:${mergeCtrlInfo.channel[i]},TimeOut:${mergeCtrlInfo.correctionTimeOut[i]},RcvTimeOut:${Math.max(...data1.openTimeSecArr)},remainingTime:${remainingTime},======================`)
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                                if (ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] == true) {
                                                                                                      ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                                      clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                                      ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                                      ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                                } else {
                                                                                                      remainingTime += 1;
                                                                                                      if (mergeCtrlInfo.targetOpen[i] > realtimeOpen) {//开棚 上次开度
                                                                                                            realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.correctionTimeOut[i]));
                                                                                                            realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.targetOpen[i]} - ${mergeCtrlInfo.lastOpen[i]})/ ${mergeCtrlInfo.correctionTimeOut[i]}=${realtimeOpen}`,)
                                                                                                      } else {
                                                                                                            ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                            realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                                      }
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                                }
                                                                                          }, 1000)
                                                                                    }
                                                                              })
                                                                        }, (mergeCtrlInfo.timeOut[i] + 2 * (i + 3)) * 1000);
                                                                  } else {//不用校正
                                                                        console.log(mergeCtrlInfo.targetOpen[i])
                                                                        if ((mergeCtrlInfo.targetOpen[i] == 100 && mergeCtrlInfo.isForceOpen[i] == true) || mergeCtrlInfo.targetOpen[i] == 241 || mergeCtrlInfo.targetOpen[i] == 240 || mergeCtrlInfo.targetOpen[i] == 0) {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, mergeCtrlInfo.lastOpen[i]);
                                                                              mergeCtrlInfo.settings[i].errCorrectionCnt = mergeCtrlInfo.settings[i].errCorrectionNumber;
                                                                              updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                              let timeOutCnt = 0;
                                                                              let realtimeOpen = 2;
                                                                              let remainingTime = mergeCtrlInfo.timeOut[i] - Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]]);//计算已工作时长
                                                                              ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                    if (timeOutCnt < mergeCtrlInfo.timeOut[i] / 2) {
                                                                                          timeOutCnt++;
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] += 1;
                                                                                          // ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, mergeCtrlInfo.lastOpen[i]);

                                                                                          remainingTime += 2;
                                                                                          if (mergeCtrlInfo.targetOpen[i] > mergeCtrlInfo.lastOpen[i]) {//开棚 上次开度
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.forceCtrlCaculateTimeSec[i]));
                                                                                                realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[强制卷膜]计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.forceCtrlCaculateTimeSec[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen >= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else if (mergeCtrlInfo.targetOpen[i] < mergeCtrlInfo.lastOpen[i]) {
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - mergeCtrlInfo.targetOpen[i]) / mergeCtrlInfo.forceCtrlCaculateTimeSec[i]));
                                                                                                realtimeOpen = realtimeOpen < mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[强制卷膜]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.forceCtrlCaculateTimeSec[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else {
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                          }
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, realtimeOpen);
                                                                                    } else {
                                                                                          console.log(`@@@@@@@@@@@@@@@@@强制卷膜完成@@@@@@@@@@@@@@@@@@`)
                                                                                          mergeCtrlInfo.settings[i].errCorrectionCnt = 0;
                                                                                          updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                    }

                                                                              }, 2000)
                                                                        } else {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, mergeCtrlInfo.lastOpen[i]);
                                                                              let remainingTime = mergeCtrlInfo.timeOut[i] - Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]]);//计算已工作时长
                                                                              console.log(`Index:${i}, Channel:${mergeCtrlInfo.channel[i]},TimeOut:${mergeCtrlInfo.timeOut[i]},RcvTimeOut:${Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]])},remainingTime:${remainingTime}======================`)
                                                                              ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              let realtimeOpen = 2;
                                                                              ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                    if (ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] == true) {
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                    } else {
                                                                                          remainingTime += 1;
                                                                                          if (mergeCtrlInfo.targetOpen[i] > mergeCtrlInfo.lastOpen[i]) {//开棚 上次开度
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.timeOut[i]));
                                                                                                realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[中间开度]计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen >= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else if (mergeCtrlInfo.targetOpen[i] < mergeCtrlInfo.lastOpen[i]) {
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - mergeCtrlInfo.targetOpen[i]) / mergeCtrlInfo.timeOut[i]));
                                                                                                realtimeOpen = realtimeOpen < mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[中间开度]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else {
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                          }
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                    }
                                                                              }, 1000)
                                                                        }
                                                                  }

                                                            }

                                                      } else {
                                                            console.log(err)
                                                            for (let i = 0; i < mergeCtrlInfo.addr.length; i++) {
                                                                  ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                            }
                                                            RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                      }

                                                })
                                                break;
                                          case "LORA_MODBUSTCP":
                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtr>】LORA_MODBUSTCP设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                WriteTimerCoils(addr, groupId, mergeCtrlInfo.openChNum.concat(mergeCtrlInfo.closeChNum), mergeCtrlInfo.openTimeSec.concat(mergeCtrlInfo.closeTimeSec), 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                      if (null == err) {
                                                            for (let i = 0; i < mergeCtrlInfo.addr.length; i++) {
                                                                  let para = {
                                                                        f_actuator_sn: mergeCtrlInfo.sn[i],
                                                                        f_actuator_addr: mergeCtrlInfo.addr[i],
                                                                        f_channel: mergeCtrlInfo.channel[i],
                                                                        staId: mergeCtrlInfo.beginStatusId[i],
                                                                        f_zone_id: mergeCtrlInfo.zoneId[i],
                                                                        f_actuator_alias: mergeCtrlInfo.alias[i],
                                                                  }
                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;

                                                                  /**
                                                                   * 需要回校正
                                                                   * 1、等待回0，关闭关行程时间
                                                                   * 2、时间到后开启
                                                                   */
                                                                  if (mergeCtrlInfo.isCorrection[i] == true) {//
                                                                        // console.log(para)
                                                                        setTimeout(() => {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, mergeCtrlInfo.lastOpen[i]);
                                                                        }, i * 100);
                                                                        let timeOutCnt = 0;
                                                                        let realtimeOpen = 2;
                                                                        let remainingTime = 0;//计算已工作时长
                                                                        ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                              if (timeOutCnt < (mergeCtrlInfo.timeOut[i] + 2 * (i - 1)) / 2) {
                                                                                    timeOutCnt++;
                                                                                    ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] += 1;
                                                                                    remainingTime += 1;
                                                                                    realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - 0) / mergeCtrlInfo.timeOut[i]));
                                                                                    realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                    // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[校正回零]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - 0)/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                    ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, realtimeOpen);
                                                                              } else {
                                                                                    console.log(`@@@@@@@@@@@@@@@@@====校正归零完成=====@@@@@@@@@@@@@@@@@@`)
                                                                                    clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                    ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                              }
                                                                        }, 2000)
                                                                        RollerCtrlTimeout[`${mergeCtrlInfo.sn[i]}`] = setTimeout(() => {
                                                                              mergeCtrlInfo.lastOpen[i] = 0;
                                                                              RollerCtrlTimeout[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, 0);
                                                                              ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              let realtimeOpen = 2;
                                                                              mergeCtrlInfo.settings[i].errCorrectionCnt = 0;
                                                                              updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                              ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              WriteTimerCoils(addr, groupId, [mergeCtrlInfo.openChNum[i], mergeCtrlInfo.closeChNum[i]], [mergeCtrlInfo.correctionOpenTimeSec[i], mergeCtrlInfo.correctionCloseTimeSec[i]], 300 + Math.random() * 300, 3, true, function (err: string | null, data1: any | null) {
                                                                                    if (null == err) {
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                          let remainingTime = mergeCtrlInfo.correctionTimeOut[i] - Math.max(...data1.openTimeSecArr);//计算已工作时长
                                                                                          console.log(`Index:${i}, Channel:${mergeCtrlInfo.channel[i]},TimeOut:${mergeCtrlInfo.correctionTimeOut[i]},RcvTimeOut:${Math.max(...data1.openTimeSecArr)},remainingTime:${remainingTime},======================`)
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                                if (ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] == true) {
                                                                                                      ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                                      clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                                      ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                                      ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                                } else {
                                                                                                      remainingTime += 1;
                                                                                                      if (mergeCtrlInfo.targetOpen[i] > realtimeOpen) {//开棚 上次开度
                                                                                                            realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.correctionTimeOut[i]));
                                                                                                            realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.targetOpen[i]} - ${mergeCtrlInfo.lastOpen[i]})/ ${mergeCtrlInfo.correctionTimeOut[i]}=${realtimeOpen}`,)
                                                                                                      } else {
                                                                                                            ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                            realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                                      }
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                                }
                                                                                          }, 1000)
                                                                                    }
                                                                              })
                                                                        }, (mergeCtrlInfo.timeOut[i] + 2 * (i + 3)) * 1000);
                                                                  } else {//不用校正
                                                                        console.log(mergeCtrlInfo.targetOpen[i])
                                                                        if ((mergeCtrlInfo.targetOpen[i] == 100 && mergeCtrlInfo.isForceOpen[i] == true) || mergeCtrlInfo.targetOpen[i] == 241 || mergeCtrlInfo.targetOpen[i] == 240 || mergeCtrlInfo.targetOpen[i] == 0) {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, mergeCtrlInfo.lastOpen[i]);
                                                                              mergeCtrlInfo.settings[i].errCorrectionCnt = mergeCtrlInfo.settings[i].errCorrectionNumber;
                                                                              updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                              let timeOutCnt = 0;
                                                                              let realtimeOpen = 2;
                                                                              let remainingTime = mergeCtrlInfo.timeOut[i] - Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]]);//计算已工作时长
                                                                              ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                    if (timeOutCnt < mergeCtrlInfo.timeOut[i] / 2) {
                                                                                          timeOutCnt++;
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] += 1;
                                                                                          // ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, mergeCtrlInfo.lastOpen[i]);

                                                                                          remainingTime += 2;
                                                                                          if (mergeCtrlInfo.targetOpen[i] > mergeCtrlInfo.lastOpen[i]) {//开棚 上次开度
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.forceCtrlCaculateTimeSec[i]));
                                                                                                realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[强制卷膜]计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.forceCtrlCaculateTimeSec[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen >= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else if (mergeCtrlInfo.targetOpen[i] < mergeCtrlInfo.lastOpen[i]) {
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - mergeCtrlInfo.targetOpen[i]) / mergeCtrlInfo.forceCtrlCaculateTimeSec[i]));
                                                                                                realtimeOpen = realtimeOpen < mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[强制卷膜]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.forceCtrlCaculateTimeSec[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else {
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                          }
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, realtimeOpen);
                                                                                    } else {
                                                                                          console.log(`@@@@@@@@@@@@@@@@@强制卷膜完成@@@@@@@@@@@@@@@@@@`)
                                                                                          mergeCtrlInfo.settings[i].errCorrectionCnt = 0;
                                                                                          updateRollerSettings(mergeCtrlInfo.sn[i], JSON.stringify(mergeCtrlInfo.settings[i]));
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                    }

                                                                              }, 2000)
                                                                        } else {
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, mergeCtrlInfo.lastOpen[i]);
                                                                              let remainingTime = mergeCtrlInfo.timeOut[i] - Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]]);//计算已工作时长
                                                                              console.log(`Index:${i}, Channel:${mergeCtrlInfo.channel[i]},TimeOut:${mergeCtrlInfo.timeOut[i]},RcvTimeOut:${Math.max(...[data.openTimeSecArr[i], data.openTimeSecArr[data.openTimeSecArr.length / 2 + i]])},remainingTime:${remainingTime}======================`)
                                                                              ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                              let realtimeOpen = 2;
                                                                              ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = setInterval(() => {
                                                                                    if (ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] == true) {
                                                                                          ACK_ROLLER_WORK_STATUS_WEB_CNT[`${mergeCtrlInfo.sn[i]}`] = 10;
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, mergeCtrlInfo.targetOpen[i]);
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${mergeCtrlInfo.sn[i]}`] = null;
                                                                                          ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                                                    } else {
                                                                                          remainingTime += 1;
                                                                                          if (mergeCtrlInfo.targetOpen[i] > mergeCtrlInfo.lastOpen[i]) {//开棚 上次开度
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] + remainingTime * (mergeCtrlInfo.targetOpen[i] - mergeCtrlInfo.lastOpen[i]) / mergeCtrlInfo.timeOut[i]));
                                                                                                realtimeOpen = realtimeOpen > mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[中间开度]计算开棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} + ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen >= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else if (mergeCtrlInfo.targetOpen[i] < mergeCtrlInfo.lastOpen[i]) {
                                                                                                realtimeOpen = Math.floor((mergeCtrlInfo.lastOpen[i] - remainingTime * (mergeCtrlInfo.lastOpen[i] - mergeCtrlInfo.targetOpen[i]) / mergeCtrlInfo.timeOut[i]));
                                                                                                realtimeOpen = realtimeOpen < mergeCtrlInfo.targetOpen[i] ? mergeCtrlInfo.targetOpen[i] : realtimeOpen;
                                                                                                realtimeOpen = realtimeOpen < 0 ? 0 : realtimeOpen;
                                                                                                console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】======[中间开度]计算关棚实时开度=======`, mergeCtrlInfo.lastOpen[i], `${mergeCtrlInfo.lastOpen[i]} - ${remainingTime}*(${mergeCtrlInfo.lastOpen[i]} - ${mergeCtrlInfo.targetOpen[i]})/ ${mergeCtrlInfo.timeOut[i]}=${realtimeOpen}`,)
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = realtimeOpen <= mergeCtrlInfo.targetOpen[i] ? true : false;
                                                                                          } else {
                                                                                                ClearRollerIntervalFlag[`${mergeCtrlInfo.sn[i]}`] = true;
                                                                                                realtimeOpen = mergeCtrlInfo.targetOpen[i];
                                                                                          }
                                                                                          ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                    }
                                                                              }, 1000)
                                                                        }
                                                                  }

                                                            }

                                                      } else {
                                                            console.log(err)
                                                            for (let i = 0; i < mergeCtrlInfo.addr.length; i++) {
                                                                  ROLLER_CTRL_CLOCK[`${mergeCtrlInfo.sn[i]}`] = false;
                                                            }
                                                            RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                      }

                                                })
                                                break;
                                          default:
                                                break;
                                    }
                              }

                        } else {
                              cntMerge++;
                        }
                  }

            }).catch((err) => {

            })

      });
}
/**
 * 单控卷膜
 * @param RedisGateway 
 * @param openSlaver_sn 
 * @param targetOpen 
 */
function rollerOpenSlaver(RedisGateway: RedisGatewayClass, LoRaComCtrl: LoRaComCtrlClass, TcpComCtrl: TcpComCtrlClass, openSlaver_sn: string, targetOpen: number, isCorrection: boolean) {
      targetOpen = targetOpen == 240 ? 0 : targetOpen
      Mysql.QueryConditionalDataFromTable('t_actuator', `f_actuator_sn='${openSlaver_sn}' AND f_actuator_type_id='B001'`).then((info) => {
            if (info.length > 0) {
                  //{"openChName":"DO_E240100B_0_2","openTravel":[10,10,10,10,10,10,10,10,10,10],"forceOpenTime":120,"openCorrection":0,"closeChName":"DO_E240100B_0_4","closeTravel":[10,10,10,10,10,10,10,10,10,10],"forceCloseTime":110,"closeCorrection":0,"errCorrectionCnt":0}
                  // console.log(info[0].f_pre_allocate3);
                  if (info[0].f_pre_allocate3) {
                        let lastOpen = parseInt(info[0].f_last_value);
                        lastOpen = isNaN(lastOpen) ? 0 : lastOpen;
                        let sn = info[0].f_actuator_sn;
                        let addr = info[0].f_actuator_addr;
                        let f_group = parseInt(info[0].f_group);
                        let f_channel = parseInt(info[0].f_channel);
                        let f_zone_id = parseInt(info[0].f_zone_id);
                        let f_actuator_alias = info[0].f_actuator_alias;
                        let settings = JSON.parse(info[0].f_pre_allocate3);
                        let openChName = settings.openChName;
                        let openTravel = settings.openTravel;
                        let forceOpenTime = settings.forceOpenTime;
                        let openCorrection = settings.openCorrection;
                        let closeChName = settings.closeChName;
                        let closeTravel = settings.closeTravel;
                        let forceCloseTime = settings.forceCloseTime;
                        let closeCorrection = settings.closeCorrection;
                        let scrapTimeSec = settings.scrapTimeSec;
                        let openChOpenTimeSec = 0;//开启通道的打开时长
                        let closeChOpenTimeSec = 0;//关闭通道打开时长
                        let isForceOpen = settings.isForceOpen ? settings.isForceOpen : false;
                        let timeOut = 0;
                        let forceCtrlCaculateTimeSec = forceOpenTime;
                        Curd.QueryTwoNewActuatorsInfo(openChName, closeChName).then((DOInfos) => {
                              // console.log(DOInfos)
                              if (DOInfos) {
                                    if (targetOpen == 240 || targetOpen == 0) {//强制全关
                                          if (lastOpen == 0 && targetOpen == 0) {
                                                // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<mergeRollerGroupCtrl>】=======已经全关了=======`)
                                                openChOpenTimeSec = 0;
                                                closeChOpenTimeSec = 0;
                                                timeOut = 0;
                                          } else {
                                                openChOpenTimeSec = 0;
                                                closeChOpenTimeSec = forceCloseTime;
                                                forceCtrlCaculateTimeSec = calculateCloseTravelTime(lastOpen, closeTravel, targetOpen, closeCorrection);
                                                timeOut = forceCloseTime;
                                          }
                                    } else if (targetOpen == 241 || (targetOpen == 100 && isForceOpen == true)) {//强制全开
                                          isForceOpen = true;//区分100和强制
                                          closeChOpenTimeSec = 0;
                                          openChOpenTimeSec = forceOpenTime;
                                          forceCtrlCaculateTimeSec = calculateOpenTravelTime(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec);
                                          timeOut = forceOpenTime;
                                    } else if (lastOpen == targetOpen) {
                                          openChOpenTimeSec = 0;
                                          closeChOpenTimeSec = 0;
                                          timeOut = 0;
                                    } else {
                                          if (lastOpen > targetOpen) {//上次开度大于设定开度,关棚计算,不计算搭边时间
                                                openChOpenTimeSec = 0;
                                                closeChOpenTimeSec = calculateCloseTravelTime(lastOpen, closeTravel, targetOpen, closeCorrection);
                                                timeOut = closeChOpenTimeSec;
                                          } else {//开棚计算,需要判断上次开度是否为0，为零需要加上搭边时间
                                                openChOpenTimeSec = calculateOpenTravelTime(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec);
                                                closeChOpenTimeSec = 0;
                                                timeOut = openChOpenTimeSec;
                                          }
                                    }

                                    let mode_driver = DOInfos[0].mode_driver;
                                    let groupId = DOInfos[0].groupId;
                                    let openChInfo = DOInfos.find((element) => {
                                          return element.name == openChName;
                                    })
                                    let closeChInfo = DOInfos.find((element) => {
                                          return element.name == closeChName;
                                    })
                                    updateRollerSettings(sn, JSON.stringify(settings));
                                    if (openChInfo != undefined && closeChInfo != undefined) {
                                          console.log(ROLLER_CTRL_CLOCK[`${sn}`])
                                          if (ROLLER_CTRL_CLOCK[`${sn}`] != true) {
                                                ROLLER_CTRL_CLOCK[`${sn}`] = true;
                                                if (!isCorrection) {//无需校准
                                                      switch (mode_driver) {
                                                            case "LoRa_ComCtrl":
                                                                  // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】LoRa_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                  // console.log(addr, [openChInfo?.channel, closeChInfo?.channel], [openChOpenTimeSec, closeChOpenTimeSec])
                                                                  if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                        clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                        ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                  }
                                                                  LoRaComCtrl.WriteTimerCoils(addr, groupId, [openChInfo?.channel, closeChInfo?.channel], [openChOpenTimeSec, closeChOpenTimeSec], 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                                        // console.log(err, data ? data.openTimeSecArr : null)
                                                                        if (null == err) {
                                                                              let para = {
                                                                                    f_actuator_sn: sn,
                                                                                    f_actuator_addr: addr,
                                                                                    f_channel: f_channel,
                                                                                    staId: 1,
                                                                                    f_zone_id: f_zone_id,
                                                                                    f_actuator_alias: f_actuator_alias,
                                                                              }
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                              if ((targetOpen == 100 && isForceOpen == true) || targetOpen == 241 || targetOpen == 0) {
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                    updateRollerSettings(sn, JSON.stringify(settings));
                                                                                    let timeOutCnt = 0;
                                                                                    let remainingTime = timeOut - Math.max(...data.openTimeSecArr);//计算已工作时长
                                                                                    let realtimeOpen = 2;
                                                                                    timeOut = Math.max(...data.openTimeSecArr);
                                                                                    ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                          if (timeOutCnt < timeOut / 2) {
                                                                                                timeOutCnt++;
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] += 1;

                                                                                                remainingTime += 1;
                                                                                                if (targetOpen > lastOpen) {//开棚 上次开度
                                                                                                      realtimeOpen = Math.floor((lastOpen + remainingTime * (targetOpen - lastOpen) / forceCtrlCaculateTimeSec));
                                                                                                      realtimeOpen = realtimeOpen > targetOpen ? targetOpen : realtimeOpen;
                                                                                                      realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                      // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算开棚实时开度=======`, lastOpen, `${lastOpen} + ${remainingTime}*(${targetOpen} - ${lastOpen})/ ${forceCtrlCaculateTimeSec}=${realtimeOpen}`,)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = realtimeOpen >= targetOpen ? true : false;
                                                                                                } else if (targetOpen < lastOpen) {
                                                                                                      realtimeOpen = Math.floor((lastOpen - remainingTime * (lastOpen - targetOpen) / forceCtrlCaculateTimeSec));
                                                                                                      realtimeOpen = realtimeOpen < targetOpen ? targetOpen : realtimeOpen;
                                                                                                      // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算关棚实时开度=======`, lastOpen, `${lastOpen} - ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${forceCtrlCaculateTimeSec}=${realtimeOpen}`,)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = realtimeOpen <= targetOpen ? true : false;
                                                                                                } else {
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = true;
                                                                                                      realtimeOpen = targetOpen;
                                                                                                }
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, realtimeOpen);
                                                                                          } else {
                                                                                                updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                                          }
                                                                                    }, 2000)
                                                                              } else {
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, lastOpen);
                                                                                    let remainingTime = timeOut - Math.max(...data.openTimeSecArr);//计算已工作时长
                                                                                    console.log(`卷膜已工作时长为：${remainingTime}秒`)
                                                                                    ClearRollerIntervalFlag[`${sn}`] = false;
                                                                                    let realtimeOpen = 2;
                                                                                    ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                          if (ClearRollerIntervalFlag[`${sn}`] == true) {
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                                          } else {

                                                                                                remainingTime += 1;
                                                                                                if (targetOpen > lastOpen) {//开棚 上次开度
                                                                                                      realtimeOpen = Math.floor((lastOpen + remainingTime * (targetOpen - lastOpen) / timeOut));
                                                                                                      realtimeOpen = realtimeOpen > targetOpen ? targetOpen : realtimeOpen;
                                                                                                      realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                      // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算开棚实时开度=======`, lastOpen, `${lastOpen} + ${remainingTime}*(${targetOpen} - ${lastOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = realtimeOpen >= targetOpen ? true : false;
                                                                                                } else if (targetOpen < lastOpen) {
                                                                                                      realtimeOpen = Math.floor((lastOpen - remainingTime * (lastOpen - targetOpen) / timeOut));
                                                                                                      realtimeOpen = realtimeOpen < targetOpen ? targetOpen : realtimeOpen;
                                                                                                      // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算关棚实时开度=======`, lastOpen, `${lastOpen} - ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = realtimeOpen <= targetOpen ? true : false;
                                                                                                } else {
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = true;
                                                                                                      realtimeOpen = targetOpen;
                                                                                                }
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                          }
                                                                                    }, 1000)
                                                                              }
                                                                        } else {
                                                                              console.log(err)
                                                                              ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                              RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                        }

                                                                  })
                                                                  break;
                                                            case "Tcp_ComCtrl":
                                                                  console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】Tcp_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                  // console.log(addr, [openChInfo?.channel, closeChInfo?.channel], [openChOpenTimeSec, closeChOpenTimeSec])
                                                                  if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                        clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                        ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                  }
                                                                  TcpComCtrl.WriteTimerCoils(addr, groupId, [openChInfo?.channel, closeChInfo?.channel], [openChOpenTimeSec, closeChOpenTimeSec], 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                                        // console.log(err, data ? data.openTimeSecArr : null)
                                                                        if (null == err) {
                                                                              let para = {
                                                                                    f_actuator_sn: sn,
                                                                                    f_actuator_addr: addr,
                                                                                    f_channel: f_channel,
                                                                                    staId: 1,
                                                                                    f_zone_id: f_zone_id,
                                                                                    f_actuator_alias: f_actuator_alias,
                                                                              }
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                              if ((targetOpen == 100 && isForceOpen == true) || targetOpen == 241 || targetOpen == 0) {
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                    updateRollerSettings(sn, JSON.stringify(settings));
                                                                                    let timeOutCnt = 0;
                                                                                    timeOut = Math.max(...data.openTimeSecArr);
                                                                                    ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                          if (timeOutCnt < timeOut / 2) {
                                                                                                timeOutCnt++;
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] += 1;
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                          } else {
                                                                                                updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                          }
                                                                                    }, 2000)
                                                                              } else {
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, lastOpen);
                                                                                    let remainingTime = timeOut - Math.max(...data.openTimeSecArr);//计算已工作时长
                                                                                    console.log(`卷膜已工作时长为：${remainingTime}秒`)
                                                                                    ClearRollerIntervalFlag[`${sn}`] = false;
                                                                                    let realtimeOpen = 2;
                                                                                    ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                          if (ClearRollerIntervalFlag[`${sn}`] == true) {
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                                          } else {

                                                                                                remainingTime += 1;
                                                                                                if (targetOpen > lastOpen) {//开棚 上次开度
                                                                                                      realtimeOpen = Math.floor((lastOpen + remainingTime * (targetOpen - lastOpen) / timeOut));
                                                                                                      realtimeOpen = realtimeOpen > targetOpen ? targetOpen : realtimeOpen;
                                                                                                      realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                      console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算开棚实时开度=======`, lastOpen, `${lastOpen} + ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = realtimeOpen >= targetOpen ? true : false;
                                                                                                } else if (targetOpen < lastOpen) {
                                                                                                      realtimeOpen = Math.floor((lastOpen - remainingTime * (lastOpen - targetOpen) / timeOut));
                                                                                                      realtimeOpen = realtimeOpen < targetOpen ? targetOpen : realtimeOpen;
                                                                                                      console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算关棚实时开度=======`, lastOpen, `${lastOpen} - ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = realtimeOpen <= targetOpen ? true : false;
                                                                                                } else {
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = true;
                                                                                                      realtimeOpen = targetOpen;
                                                                                                }
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                          }
                                                                                    }, 1000)
                                                                              }
                                                                        } else {
                                                                              console.log(err)
                                                                              ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                              RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                        }

                                                                  })
                                                                  break;
                                                            case "LORA_MODBUSTCP":
                                                                  console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】LORA_MODBUSTCP设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                  // console.log(addr, [openChInfo?.channel, closeChInfo?.channel], [openChOpenTimeSec, closeChOpenTimeSec])
                                                                  if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                        clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                        ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                  }
                                                                  WriteTimerCoils(addr, groupId, [openChInfo?.channel, closeChInfo?.channel], [openChOpenTimeSec, closeChOpenTimeSec], 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                                        // console.log(err, data ? data.openTimeSecArr : null)
                                                                        if (null == err) {
                                                                              let para = {
                                                                                    f_actuator_sn: sn,
                                                                                    f_actuator_addr: addr,
                                                                                    f_channel: f_channel,
                                                                                    staId: 1,
                                                                                    f_zone_id: f_zone_id,
                                                                                    f_actuator_alias: f_actuator_alias,
                                                                              }
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                              if ((targetOpen == 100 && isForceOpen == true) || targetOpen == 241 || targetOpen == 0) {
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                    updateRollerSettings(sn, JSON.stringify(settings));
                                                                                    let timeOutCnt = 0;
                                                                                    timeOut = Math.max(...data.openTimeSecArr);
                                                                                    ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                          if (timeOutCnt < timeOut / 2) {
                                                                                                timeOutCnt++;
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] += 1;
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                          } else {
                                                                                                updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                          }
                                                                                    }, 2000)
                                                                              } else {
                                                                                    ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, lastOpen);
                                                                                    let remainingTime = timeOut - Math.max(...data.openTimeSecArr);//计算已工作时长
                                                                                    console.log(`卷膜已工作时长为：${remainingTime}秒`)
                                                                                    ClearRollerIntervalFlag[`${sn}`] = false;
                                                                                    let realtimeOpen = 2;
                                                                                    ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                          if (ClearRollerIntervalFlag[`${sn}`] == true) {
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                                          } else {

                                                                                                remainingTime += 1;
                                                                                                if (targetOpen > lastOpen) {//开棚 上次开度
                                                                                                      realtimeOpen = Math.floor((lastOpen + remainingTime * (targetOpen - lastOpen) / timeOut));
                                                                                                      realtimeOpen = realtimeOpen > targetOpen ? targetOpen : realtimeOpen;
                                                                                                      realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                      console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算开棚实时开度=======`, lastOpen, `${lastOpen} + ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = realtimeOpen >= targetOpen ? true : false;
                                                                                                } else if (targetOpen < lastOpen) {
                                                                                                      realtimeOpen = Math.floor((lastOpen - remainingTime * (lastOpen - targetOpen) / timeOut));
                                                                                                      realtimeOpen = realtimeOpen < targetOpen ? targetOpen : realtimeOpen;
                                                                                                      console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算关棚实时开度=======`, lastOpen, `${lastOpen} - ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = realtimeOpen <= targetOpen ? true : false;
                                                                                                } else {
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = true;
                                                                                                      realtimeOpen = targetOpen;
                                                                                                }
                                                                                                ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                          }
                                                                                    }, 1000)
                                                                              }
                                                                        } else {
                                                                              console.log(err)
                                                                              ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                              RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                        }

                                                                  })
                                                                  break;
                                                            default:
                                                                  break;
                                                      }
                                                } else {
                                                      // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】LoRa_ComCtrl校准归0中<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<`)
                                                      let openChannel = openChInfo?.channel;
                                                      let closeChannel = closeChInfo?.channel;
                                                      let scrapTimeSec = settings.scrapTimeSec;
                                                      //自动校准回0
                                                      switch (mode_driver) {
                                                            case "LoRa_ComCtrl":
                                                                  // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】LoRa_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                  if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                        clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                        ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                  }
                                                                  LoRaComCtrl.WriteTimerCoils(addr, groupId, [openChannel, closeChannel], [0, forceCloseTime], 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                                        // console.log(err, data ? data.openTimeSecArr : null)
                                                                        if (null == err) {
                                                                              let para = {
                                                                                    f_actuator_sn: sn,
                                                                                    f_actuator_addr: addr,
                                                                                    f_channel: f_channel,
                                                                                    staId: 16,
                                                                                    f_zone_id: f_zone_id,
                                                                                    f_actuator_alias: f_actuator_alias,
                                                                              }
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, lastOpen);
                                                                              console.log(`归0所需时长剩余：${Math.max(...data.openTimeSecArr)}秒`)
                                                                              RollerCtrlTimeout[`${sn}`] = setTimeout(() => {
                                                                                    RollerCtrlTimeout[`${sn}`] = null;
                                                                                    updateRollerSettings(sn, JSON.stringify(settings));
                                                                                    lastOpen = 0;
                                                                                    openChOpenTimeSec = calculateOpenTravelTime(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec);
                                                                                    closeChOpenTimeSec = 0;
                                                                                    timeOut = openChOpenTimeSec;
                                                                                    // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】LoRa_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                                    // console.log(addr, [openChannel, closeChannel], [openChOpenTimeSec, closeChOpenTimeSec])
                                                                                    if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                    }
                                                                                    LoRaComCtrl.WriteTimerCoils(addr, groupId, [openChannel, closeChannel], [openChOpenTimeSec, closeChOpenTimeSec], 300 + Math.random() * 300, 3, true, function (err: string | null, data: any | null) {
                                                                                          //  console.log(err, data ? data.openTimeSecArr : null)
                                                                                          if (null == err) {
                                                                                                let para = {
                                                                                                      f_actuator_sn: sn,
                                                                                                      f_actuator_addr: addr,
                                                                                                      f_channel: f_channel,
                                                                                                      staId: 1,
                                                                                                      f_zone_id: f_zone_id,
                                                                                                      f_actuator_alias: f_actuator_alias,
                                                                                                }
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                if ((targetOpen == 100 && isForceOpen == true) || targetOpen == 241 || targetOpen == 0) {
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                                      updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                      let timeOutCnt = 0;
                                                                                                      ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                                            if (timeOutCnt < timeOut / 2) {
                                                                                                                  timeOutCnt++;
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] += 1;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                                            } else {
                                                                                                                  updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                                  clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                                  ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                            }
                                                                                                      }, 2000)
                                                                                                } else {
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, lastOpen);
                                                                                                      let remainingTime = timeOut - Math.max(...data.openTimeSecArr);//计算已工作时长
                                                                                                      console.log(`卷膜已工作时长为：${remainingTime}秒`)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = false;
                                                                                                      let realtimeOpen = 2;
                                                                                                      ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                                            if (ClearRollerIntervalFlag[`${sn}`] == true) {
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                                  clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                                  ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                                                                  ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                            } else {
                                                                                                                  remainingTime += 1;
                                                                                                                  if (targetOpen > lastOpen) {//开棚 上次开度
                                                                                                                        realtimeOpen = Math.floor((lastOpen + remainingTime * (targetOpen - lastOpen) / timeOut));
                                                                                                                        realtimeOpen = realtimeOpen > targetOpen ? targetOpen : realtimeOpen;
                                                                                                                        realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                                        console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算开棚实时开度=======`, lastOpen, `${lastOpen} + ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = realtimeOpen >= targetOpen ? true : false;
                                                                                                                  } else if (targetOpen < lastOpen) {
                                                                                                                        realtimeOpen = Math.floor((lastOpen - remainingTime * (lastOpen - targetOpen) / timeOut));
                                                                                                                        realtimeOpen = realtimeOpen < targetOpen ? targetOpen : realtimeOpen;
                                                                                                                        console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算关棚实时开度=======`, lastOpen, `${lastOpen} - ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = realtimeOpen <= targetOpen ? true : false;
                                                                                                                  } else {
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = true;
                                                                                                                        realtimeOpen = targetOpen;
                                                                                                                  }
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                                            }
                                                                                                      }, 1000)
                                                                                                }
                                                                                          } else {
                                                                                                console.log(err)
                                                                                                RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                                          }

                                                                                    })
                                                                              }, Math.max(...data.openTimeSecArr) * 1000)
                                                                        } else {
                                                                              console.log(err)
                                                                              ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                              RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                        }

                                                                  })

                                                                  break;
                                                            case "Tcp_ComCtrl":
                                                                  console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】Tcp_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                  if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                        clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                        ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                  }
                                                                  TcpComCtrl.WriteTimerCoils(addr, groupId, [openChannel, closeChannel], [0, forceCloseTime], 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                                        // console.log(err, data ? data.openTimeSecArr : null)
                                                                        if (null == err) {
                                                                              let para = {
                                                                                    f_actuator_sn: sn,
                                                                                    f_actuator_addr: addr,
                                                                                    f_channel: f_channel,
                                                                                    staId: 16,
                                                                                    f_zone_id: f_zone_id,
                                                                                    f_actuator_alias: f_actuator_alias,
                                                                              }
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, lastOpen);
                                                                              console.log(`归0所需时长剩余：${Math.max(...data.openTimeSecArr)}秒`)
                                                                              RollerCtrlTimeout[`${sn}`] = setTimeout(() => {
                                                                                    RollerCtrlTimeout[`${sn}`] = null;
                                                                                    updateRollerSettings(sn, JSON.stringify(settings));
                                                                                    lastOpen = 0;
                                                                                    openChOpenTimeSec = calculateOpenTravelTime(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec);
                                                                                    closeChOpenTimeSec = 0;
                                                                                    timeOut = openChOpenTimeSec;
                                                                                    // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】LoRa_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                                    // console.log(addr, [openChannel, closeChannel], [openChOpenTimeSec, closeChOpenTimeSec])
                                                                                    if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                    }
                                                                                    TcpComCtrl.WriteTimerCoils(addr, groupId, [openChannel, closeChannel], [openChOpenTimeSec, closeChOpenTimeSec], 300 + Math.random() * 300, 3, true, function (err: string | null, data: any | null) {
                                                                                          //  console.log(err, data ? data.openTimeSecArr : null)
                                                                                          if (null == err) {
                                                                                                let para = {
                                                                                                      f_actuator_sn: sn,
                                                                                                      f_actuator_addr: addr,
                                                                                                      f_channel: f_channel,
                                                                                                      staId: 1,
                                                                                                      f_zone_id: f_zone_id,
                                                                                                      f_actuator_alias: f_actuator_alias,
                                                                                                }
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                if ((targetOpen == 100 && isForceOpen == true) || targetOpen == 241 || targetOpen == 0) {
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                                      updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                      let timeOutCnt = 0;
                                                                                                      ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                                            if (timeOutCnt < timeOut / 2) {
                                                                                                                  timeOutCnt++;
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] += 1;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                                            } else {
                                                                                                                  updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                                  clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                                  ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                            }
                                                                                                      }, 2000)
                                                                                                } else {
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, lastOpen);
                                                                                                      let remainingTime = timeOut - Math.max(...data.openTimeSecArr);//计算已工作时长
                                                                                                      console.log(`卷膜已工作时长为：${remainingTime}秒`)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = false;
                                                                                                      let realtimeOpen = 2;
                                                                                                      ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                                            if (ClearRollerIntervalFlag[`${sn}`] == true) {
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                                  clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                                  ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                            } else {
                                                                                                                  remainingTime += 1;
                                                                                                                  if (targetOpen > lastOpen) {//开棚 上次开度
                                                                                                                        realtimeOpen = Math.floor((lastOpen + remainingTime * (targetOpen - lastOpen) / timeOut));
                                                                                                                        realtimeOpen = realtimeOpen > targetOpen ? targetOpen : realtimeOpen;
                                                                                                                        realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                                        console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算开棚实时开度=======`, lastOpen, `${lastOpen} + ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = realtimeOpen >= targetOpen ? true : false;
                                                                                                                  } else if (targetOpen < lastOpen) {
                                                                                                                        realtimeOpen = Math.floor((lastOpen - remainingTime * (lastOpen - targetOpen) / timeOut));
                                                                                                                        realtimeOpen = realtimeOpen < targetOpen ? targetOpen : realtimeOpen;
                                                                                                                        console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算关棚实时开度=======`, lastOpen, `${lastOpen} - ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = realtimeOpen <= targetOpen ? true : false;
                                                                                                                  } else {
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = true;
                                                                                                                        realtimeOpen = targetOpen;
                                                                                                                  }
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                                            }
                                                                                                      }, 1000)
                                                                                                }
                                                                                          } else {
                                                                                                console.log(err)
                                                                                                RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                                          }

                                                                                    })
                                                                              }, Math.max(...data.openTimeSecArr) * 1000)
                                                                        } else {
                                                                              console.log(err)
                                                                              ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                              RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                        }

                                                                  })

                                                                  break;
                                                            case "LORA_MODBUSTCP":
                                                                  console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】LORA_MODBUSTCP设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                  if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                        clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                        ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                  }
                                                                  WriteTimerCoils(addr, groupId, [openChannel, closeChannel], [0, forceCloseTime], 300 + Math.random() * 300, 2, true, function (err: string | null, data: any | null) {
                                                                        // console.log(err, data ? data.openTimeSecArr : null)
                                                                        if (null == err) {
                                                                              let para = {
                                                                                    f_actuator_sn: sn,
                                                                                    f_actuator_addr: addr,
                                                                                    f_channel: f_channel,
                                                                                    staId: 16,
                                                                                    f_zone_id: f_zone_id,
                                                                                    f_actuator_alias: f_actuator_alias,
                                                                              }
                                                                              ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                              ackRollerRealtimeWorkingStatus(RedisGateway, para, 16, lastOpen);
                                                                              console.log(`归0所需时长剩余：${Math.max(...data.openTimeSecArr)}秒`)
                                                                              RollerCtrlTimeout[`${sn}`] = setTimeout(() => {
                                                                                    RollerCtrlTimeout[`${sn}`] = null;
                                                                                    updateRollerSettings(sn, JSON.stringify(settings));
                                                                                    lastOpen = 0;
                                                                                    openChOpenTimeSec = calculateOpenTravelTime(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec);
                                                                                    closeChOpenTimeSec = 0;
                                                                                    timeOut = openChOpenTimeSec;
                                                                                    // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】LoRa_ComCtrl设备控制》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》`)
                                                                                    // console.log(addr, [openChannel, closeChannel], [openChOpenTimeSec, closeChOpenTimeSec])
                                                                                    if (ROLLER_CTRL_INTERVAL[`${sn}`] != null) {
                                                                                          clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                          ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                    }
                                                                                    WriteTimerCoils(addr, groupId, [openChannel, closeChannel], [openChOpenTimeSec, closeChOpenTimeSec], 300 + Math.random() * 300, 3, true, function (err: string | null, data: any | null) {
                                                                                          //  console.log(err, data ? data.openTimeSecArr : null)
                                                                                          if (null == err) {
                                                                                                let para = {
                                                                                                      f_actuator_sn: sn,
                                                                                                      f_actuator_addr: addr,
                                                                                                      f_channel: f_channel,
                                                                                                      staId: 1,
                                                                                                      f_zone_id: f_zone_id,
                                                                                                      f_actuator_alias: f_actuator_alias,
                                                                                                }
                                                                                                ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                if ((targetOpen == 100 && isForceOpen == true) || targetOpen == 241 || targetOpen == 0) {
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                                      updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                      let timeOutCnt = 0;
                                                                                                      ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                                            if (timeOutCnt < timeOut / 2) {
                                                                                                                  timeOutCnt++;
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] += 1;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 2, lastOpen);
                                                                                                            } else {
                                                                                                                  updateRollerSettings(sn, JSON.stringify(settings));
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                                  clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                                  ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                            }
                                                                                                      }, 2000)
                                                                                                } else {
                                                                                                      ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, lastOpen);
                                                                                                      let remainingTime = timeOut - Math.max(...data.openTimeSecArr);//计算已工作时长
                                                                                                      console.log(`卷膜已工作时长为：${remainingTime}秒`)
                                                                                                      ClearRollerIntervalFlag[`${sn}`] = false;
                                                                                                      let realtimeOpen = 2;
                                                                                                      ROLLER_CTRL_INTERVAL[`${sn}`] = setInterval(() => {
                                                                                                            if (ClearRollerIntervalFlag[`${sn}`] == true) {
                                                                                                                  ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 10;
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 4, targetOpen);
                                                                                                                  clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                                                                                                                  ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                                                                                                            } else {
                                                                                                                  remainingTime += 1;
                                                                                                                  if (targetOpen > lastOpen) {//开棚 上次开度
                                                                                                                        realtimeOpen = Math.floor((lastOpen + remainingTime * (targetOpen - lastOpen) / timeOut));
                                                                                                                        realtimeOpen = realtimeOpen > targetOpen ? targetOpen : realtimeOpen;
                                                                                                                        realtimeOpen = realtimeOpen > 100 ? 100 : realtimeOpen;
                                                                                                                        console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算开棚实时开度=======`, lastOpen, `${lastOpen} + ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = realtimeOpen >= targetOpen ? true : false;
                                                                                                                  } else if (targetOpen < lastOpen) {
                                                                                                                        realtimeOpen = Math.floor((lastOpen - remainingTime * (lastOpen - targetOpen) / timeOut));
                                                                                                                        realtimeOpen = realtimeOpen < targetOpen ? targetOpen : realtimeOpen;
                                                                                                                        console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】======计算关棚实时开度=======`, lastOpen, `${lastOpen} - ${remainingTime}*(${lastOpen} - ${targetOpen})/ ${timeOut}=${realtimeOpen}`,)
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = realtimeOpen <= targetOpen ? true : false;
                                                                                                                  } else {
                                                                                                                        ClearRollerIntervalFlag[`${sn}`] = true;
                                                                                                                        realtimeOpen = targetOpen;
                                                                                                                  }
                                                                                                                  ackRollerRealtimeWorkingStatus(RedisGateway, para, 1, realtimeOpen);
                                                                                                            }
                                                                                                      }, 1000)
                                                                                                }
                                                                                          } else {
                                                                                                console.log(err)
                                                                                                RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                                          }

                                                                                    })
                                                                              }, Math.max(...data.openTimeSecArr) * 1000)
                                                                        } else {
                                                                              console.log(err)
                                                                              ROLLER_CTRL_CLOCK[`${sn}`] = false;
                                                                              RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'failure', err, null);
                                                                        }

                                                                  })

                                                                  break;
                                                            default:
                                                                  break;
                                                      }
                                                }
                                          } else {
                                                console.log(`=========${f_actuator_alias} 控制锁定中，等待解锁或强制停止解锁=======`)

                                          }


                                    }
                              }
                        }).catch((err) => {

                        })

                  }
            } else {
                  // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<rollerOpenSlaver>】设备不存在`)
            }
      })
}
/**
 * 计算关闭行程时间
 * @param lastOpen 
 * @param closeTravel 
 * @param targetOpen 
 * @param closeCorrection 
 * @returns 计算关闭时间
 * @example
 * console.log(calculateCloseTravelTime(95, [10, 10, 10, 10, 10, 10, 10, 10, 10, 10], 65, 0))
 */
function calculateCloseTravelTime(lastOpen: number, closeTravel: number[], targetOpen: number, closeCorrection): number {
      /*
      * sectionIndex 0    1   2   3   4   5   6   7   8   9   10
      * closeSection 100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0
      *              S0   S1  S2  S3  S4
      * 
      * travelindex     0   1   2   3   4   5   6   7   8   9
      * closeTravel     A0  A1  A2  A3  A4  A5  A6  A7  A8  A9
      *            
      *                last m1 target
      * example         95      75
      * startIndex      1
      * stopIndex               3
      * travelindex     0   1   2
      * 开始段计算：(lastOpen-closeSection[startIndex])/10*closeTravel[startIndex - 1]=(lastOpen-S1)/10*A0=(95-90)/10*A0
      * 结束段计算：(closeSection[stopIndex-1]-targetOpen)/10*closeTravel[stopIndex - 1]=(S2-targetOpen)/10*A2=(80-75)/10*A2
      * 中间段计算：
      *           let caculateMiddleOpen = 0;
      *           for(i=startIndex;i<stopIndex-1;i++){
      *              caculateMiddleOpen+=closeTravel[i];
      *           }
      * 
      */
      targetOpen = targetOpen == 241 ? 100 : targetOpen == 240 ? 0 : targetOpen;
      let closeSection = [100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0];
      let startIndex = closeSection.findIndex((data) => {
            return data == Math.floor(lastOpen / 10) * 10;//计算停止区间位置
      })
      let stopIndex = closeSection.findIndex((data) => {
            return data == Math.floor(targetOpen / 10) * 10;//计算停止区间位置
      })
      let closeChOpenTimeSec = 0
      if (lastOpen == 100) {//无需计算开始
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】\x1b[30;35m/*================================关闭时间计算======================================\nstartIndex:${startIndex},stopIndex:${stopIndex}`)
            let caculateBeginOpen = 0;//开始段计算
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】开始段计算：为全开起始，计算正在中间段`)
            let caculateMiddleOpen = 0;
            let str = `中间段计算：0`
            let str1 = `0`;
            for (let i = 0; i < stopIndex - 1; i++) {
                  caculateMiddleOpen += closeTravel[i];
                  str = `${str}+A${i}`
                  str1 = `${str1}+${closeTravel[i]}`
            }
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】${str}=${str1}=${caculateMiddleOpen}`)
            let caculateEndOpen = Math.floor(((closeSection[stopIndex - 1] - targetOpen) * closeTravel[stopIndex - 1]) / 10);//结束段计算
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】结束段计算：((S${stopIndex - 1}-targetOpen)*A${stopIndex - 1}/10= ((${closeSection[stopIndex - 1]} - ${targetOpen}) * ${closeTravel[stopIndex - 1]}) / 10=${caculateEndOpen}`)
            closeChOpenTimeSec = caculateBeginOpen + caculateMiddleOpen + caculateEndOpen + closeCorrection;
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】closeChOpenTimeSec=caculateBeginOpen+caculateMiddleOpen+caculateEndOpen+closeCorrection=${caculateBeginOpen}+${caculateMiddleOpen}+${caculateEndOpen}+${closeCorrection}=${closeChOpenTimeSec}`)
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】从 ${lastOpen}% 关到 ${targetOpen}% 所需时间为：${closeChOpenTimeSec} 秒\n=====================================================================================\x1b[30;37m`)

      } else {
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】\x1b[30;35m/*================================关闭时间计算======================================\nstartIndex:${startIndex},stopIndex:${stopIndex}`)
            let caculateBeginOpen = Math.floor((lastOpen - closeSection[startIndex]) / 10 * closeTravel[startIndex - 1]);//开始段计算
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】开始段计算：(lastOpen-S${startIndex})/10*A${startIndex - 1}=(${lastOpen}-${closeSection[startIndex]})/10*${closeTravel[startIndex - 1]}=${caculateBeginOpen}`)
            let caculateEndOpen = Math.floor((closeSection[stopIndex - 1] - targetOpen) / 10 * closeTravel[stopIndex - 1]);//结束段计算
            let caculateMiddleOpen = 0;
            let str = `中间段计算：0`
            let str1 = `0`;
            for (let i = startIndex; i < stopIndex - 1; i++) {
                  caculateMiddleOpen += closeTravel[i];
                  str = `${str}+A${i}`
                  str1 = `${str1}+${closeTravel[i]}`
            }
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】${str}=${str1}=${caculateMiddleOpen}`)
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】结束段计算：(S${stopIndex - 1}-targetOpen)/10*A${stopIndex - 1}=(${closeSection[stopIndex - 1]}-${targetOpen})/10*${closeTravel[stopIndex - 1]}=${caculateBeginOpen}`)
            closeChOpenTimeSec = caculateBeginOpen + caculateMiddleOpen + caculateEndOpen + closeCorrection;
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】closeChOpenTimeSec=caculateBeginOpen+caculateMiddleOpen+caculateEndOpen+closeCorrection=${caculateBeginOpen}+${caculateMiddleOpen}+${caculateEndOpen}+${closeCorrection}=${closeChOpenTimeSec}`)
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/calculateCloseTravelTime】从 ${lastOpen}% 关到 ${targetOpen}% 所需时间为：${closeChOpenTimeSec} 秒\n=====================================================================================\x1b[30;37m`)

      }
      return closeChOpenTimeSec;
}



/**
 * 计算开棚时间
 * @param lastOpen 上次开度
 * @param openTravel 开启行程数组
 * @param targetOpen 目标开度
 * @param openCorrection 开启偏差
 * @param scrapTimeSec 搭边时间
 * @returns 计算打开时间
 * @example
 * console.log(calculateOpenTravelTime(5, [10, 10, 10, 10, 10, 10, 10, 10, 10], 35, 0, 0))
 */
function calculateOpenTravelTime(lastOpen: number, openTravel: number[], targetOpen: number, openCorrection: number, scrapTimeSec: number): number {
      /*
      * sectionIndex 0   1    2    3    4    5    6    7    8    9    10
      * openSection  0 , 10 , 20 , 30 , 40 , 50 , 60 , 70 , 80 , 90 , 100
      *              S0  S1   S2   S3   S4   S4   S6   S7   S8   S9   S10
      * 
      * 
      * travelindex    0    1    2    3    4    5    6    7    8    9
      * openTravel     A0   A1   A2   A3   A4   A5   A6   A7   A8   A9
      *            
      *               last  m   target
      * example        5         25
      * startIndex     0
      * stopIndex                2
      * travelindex    0    1    2
      * 开始段计算：(openSection[startIndex+1]-lastOpen)*openTravel[startIndex]=(S1-laseOpen)/10*A0=(10-5)/10*A0
      * 结束段计算：(targetOpen-openSection[stopIndex])*openTravel[stopIndex]=(targetOpen-S2)/10*A2=(25-20)/10*A2
      * 中间段计算：
      *           let caculateMiddleOpen = 0;
      *           for(i=startIndex+1;i<stopIndex;i++){
      *              caculateMiddleOpen+=openTravel[i];
      *           }
      * 
      */
      // console.log(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec)
      targetOpen = targetOpen == 241 ? 100 : targetOpen == 240 ? 0 : targetOpen;
      let openSection = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
      let startIndex = openSection.findIndex((data) => {
            return data == Math.floor(lastOpen / 10) * 10;//计算停止区间位置
      })
      let stopIndex = openSection.findIndex((data) => {
            return data == Math.floor(targetOpen / 10) * 10;//计算停止区间位置
      })
      console.log(lastOpen, openTravel, targetOpen, openCorrection, scrapTimeSec)
      // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】\x1b[30;35m/*================================开启时间计算======================================\nstartIndex:${startIndex},stopIndex:${stopIndex}`)
      let openChOpenTimeSec = 0;
      if (lastOpen != 0) {
            let caculateBeginOpen = Math.floor((openSection[startIndex + 1] - lastOpen) / 10 * openTravel[startIndex]);//开始段计算
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】开始段计算：(S${startIndex + 1}-laseOpen)/10*A${startIndex}=(${openSection[startIndex + 1]}-${lastOpen})/10*${openTravel[startIndex]}=${caculateBeginOpen}`)
            let caculateEndOpen = 0;
            if (targetOpen != 100) {
                  caculateEndOpen = Math.floor((targetOpen - openSection[stopIndex]) / 10 * openTravel[stopIndex]);//结束段计算
                  // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】结束段计算：(targetOpen-S${stopIndex})/10*A${stopIndex}=(${targetOpen}-${openSection[stopIndex]})/10*${openTravel[stopIndex]}=${caculateEndOpen}`)
            }
            let caculateMiddleOpen = 0;
            let str = `中间段计算：0`
            let str1 = `0`;
            for (let i = startIndex + 1; i < stopIndex; i++) {
                  caculateMiddleOpen += openTravel[i];
                  str = `${str}+A${i}`
                  str1 = `${str1}+${openTravel[i]}`
            }
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】${str}=${str1}=${caculateMiddleOpen}`)
            openChOpenTimeSec = caculateBeginOpen + caculateMiddleOpen + caculateEndOpen + openCorrection;
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】closeChOpenTimeSec=caculateBeginOpen+caculateMiddleOpen+caculateEndOpen+openCorrection=${caculateBeginOpen}+${caculateMiddleOpen}+${caculateEndOpen}+${openChOpenTimeSec}=${openChOpenTimeSec}`)
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】从 ${lastOpen}% 开到 ${targetOpen}% 所需时间为：${openChOpenTimeSec} 秒\n=====================================================================================\x1b[30;37m`)
      } else {
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】开始段计算：开启与关闭在同一开度区间内，只计算一段`)
            let caculateBeginOpen = 0;
            let caculateMiddleOpen = 0;
            let str = `中间段计算：0`
            let str1 = `0`;
            for (let i = 0; i < stopIndex; i++) {
                  caculateMiddleOpen += openTravel[i];
                  str = `${str}+A${i}`
                  str1 = `${str1}+${openTravel[i]}`
            }
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】${str}=${str1}=${caculateMiddleOpen}`)
            let caculateEndOpen = 0;
            if (targetOpen != 100) {
                  caculateEndOpen = Math.floor((targetOpen - openSection[stopIndex]) / 10 * openTravel[stopIndex]);//结束段计算
                  // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】结束段计算：(targetOpen-S${stopIndex})/10*A${stopIndex}=(${targetOpen}-${openSection[stopIndex]})/10*${openTravel[stopIndex]}=${caculateEndOpen}`)
            } openChOpenTimeSec = caculateBeginOpen + caculateMiddleOpen + caculateEndOpen + openCorrection + scrapTimeSec;
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】closeChOpenTimeSec=caculateBeginOpen+caculateMiddleOpen+caculateEndOpen+openCorrection+scrapTimeSec=${caculateBeginOpen}+${caculateMiddleOpen}+${caculateEndOpen}+${openChOpenTimeSec}+ ${scrapTimeSec}=${openChOpenTimeSec}`)
            // console.log(`${new Date().toLocaleString()}【actuatorCmd.ts/<calculateOpenTravelTime>】从 ${lastOpen}% 开到 ${targetOpen}% 所需时间为：${openChOpenTimeSec} 秒\n=====================================================================================\x1b[30;37m`)
      }

      return openChOpenTimeSec;
}



interface AckRollerInfo {
      f_actuator_sn: string,
      f_actuator_addr: string,
      f_channel: number,
      staId: number,
      f_zone_id: number,
      f_actuator_alias: string,
}


var ACK_ROLLER_WORK_STATUS_WEB_CNT = {};
/**
 * 上报卷膜实时工作 状态
 * @param RedisGateway 
 * @param param 
 * @param staId 
 * @param openRate 
 */
function ackRollerRealtimeWorkingStatus(RedisGateway: RedisGatewayClass, param: AckRollerInfo, staId: number, openRate: number) {
      //电流计算
      //                   0          1            2           3           4            5                  6              7             8               9            10              11          12           13       14         15             16              
      let statusDoc = ["出厂模式", "正在卷膜", "正在强制卷膜", "正在重置行程", "卷膜完成", "强制卷膜完成", "到达重置行程起始位置", "重置行程完成", "强制停止成功", "到达限位等待确认", "电机过流", "电机储存信息异常", "上限位异常", "下限位异常", "电机异常", "未知开度", "自动校准开度回零中"];

      // console.log(param)
      openRate = openRate == 241 ? 100 : openRate == 240 ? 0 : openRate;
      let sn = param.f_actuator_sn;
      let addr = param.f_actuator_addr;
      let channel = param.f_channel;
      let status = statusDoc[staId];
      let zoneId = param.f_zone_id;
      let f_actuator_alias = param.f_actuator_alias;
      let value = (status == "正在卷膜" || status == "正在强制卷膜") ? 3000 : 0;
      if (status == '正在强制卷膜' && (openRate == 100 || openRate == 0)) {
            status = '正在确认限位'
      }
      if (status == '卷膜完成' || status == '强制卷膜完成' || status == '强制停止成功') {
            ROLLER_CTRL_CLOCK[`${sn}`] = false;
      }
      let allocate = `${openRate.toString(16).padStart(2, "0")}5DC00014${value.toString(16).toUpperCase().padStart(4, "0")}03F1115300000000`;
      let actuatorData = {
            "addr": addr,
            "channel": channel,
            "status": status,
            "allocate": allocate,
            "rssi": 31,
            "csq": 31,
            "vol": 24000,
            "t": moment().format('YYYY-MM-DD HH:mm:ss')
      }

      // console.log(JSON.stringify(actuatorData))
      updateRollerLastValue(sn, openRate, status, allocate);
      if (ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] >= 5) {
            if (staId == 4 || staId == 5) {
                  clearInterval(ROLLER_CTRL_INTERVAL[`${sn}`]);
                  ROLLER_CTRL_INTERVAL[`${sn}`] = null;
                  clearInterval(RollerCtrlTimeout[`${sn}`]);
                  RollerCtrlTimeout[`${sn}`] = null;
            }
            console.log(new Date().toLocaleString(), "\x1b[30;32m【actuatorCmd.ts/<ackRollerRealtimeWorkingStatus>】[实时状态]区域为" + "zoneId:(" + zoneId + ")" + "的LoRa设备" + addr + "(" + f_actuator_alias + ")" + `开度：${openRate}%,` + "实时状态为：" + status + ' (' + staId + ') allocate： ' + allocate + "\x1b[30;37m")
            RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'success', "[实时状态]区域为" + "zoneId:(" + zoneId + ")" + "的LoRa设备" + addr + "(" + f_actuator_alias + ")" + "实时状态为：" + status + ' (' + staId + ') allocate： ' + allocate, [actuatorData]);
            ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`] = 0;
      } else {
            ACK_ROLLER_WORK_STATUS_WEB_CNT[`${sn}`]++;
      }

}


/**
 * 更新某sn卷膜最后状态
 * @param {*} sn 
 * @param {*} openRate 
 */
function updateRollerLastValue(sn: string, openRate: number, status: string, allocate: string) {
      Mysql.UpdateParamsIntoTableWhereCondition(`t_actuator`, `f_actuator_sn='${sn}'`, `f_last_value='${openRate}',f_actuator_status='${status}',f_actuator_allocate='${allocate}',f_actuator_edit_time='${moment().format('YYYY-MM-DD HH:mm:ss')}'`).then((sta) => {

      })
}

/**
 * 更新某sn卷膜最后状态
 * @param {*} sn 
 * @param {*} settings 
 */
function updateRollerSettings(sn: string, settings: string) {
      Mysql.UpdateParamsIntoTableWhereCondition(`t_actuator`, `f_actuator_sn='${sn}'`, `f_pre_allocate3='${settings}'`).then((sta) => {

      })
}

interface RollerInfo {
      zoneId: number,
      sn: string,
      groupIdArray: string,
      name: string,
      addr: string,
      openChName: string,
      openTravel: number[],
      forceOpenTime: number,
      openCorrection: number,
      closeChName: string,
      closeTravel: number[],
      forceCloseTime: number,
      closeCorrection: number,
      scrapTimeSec: number,
      errCorrectionNumber: number,
      isUsedAI: boolean,
      AIChName: string,
      isForceOpen: boolean
}

function queryAllRollerInfos(RedisGateway: RedisGatewayClass, qryId: string) {
      Mysql.QueryConditionalDataFromTable(`t_actuator`, `f_actuator_type="LoRa_Roller" AND f_actuator_type_id="B001"`).then((rollerInfos) => {
            console.log(rollerInfos)
            let rollersInfo: RollerInfo[] = [];
            if (rollerInfos.length > 0) {
                  for (let i = 0; i < rollerInfos.length; i++) {
                        // console.log(roller.f_pre_allocate3)
                        // {  "openChName": "DO_FB2D1D12_0_00",
                        //     "openTravel": [34, 34, 34, 34, 34, 34, 34, 34, 34, 34],
                        //     "forceOpenTime": 120,
                        //     "openCorrection": 0,
                        //     "closeChName": "DO_FB2D1D12_0_01",
                        //     "closeTravel": [33, 33, 33, 33, 33, 33, 33, 33, 33, 33],
                        //     "forceCloseTime": 360,
                        //     "closeCorrection": 0,
                        //     "scrapTimeSec": 0,
                        //     "errCorrectionNumber": 10,
                        //     "isForceOpen": true,
                        //     "isUsedAI": true,
                        //     "AIChName": "AI_FB2D1D12_0_00",
                        //     "errCorrectionCnt": 0
                        // }
                        let settings = JSON.parse(rollerInfos[i].f_pre_allocate3);
                        if (Object.keys(settings).length > 0) {
                              let obj: RollerInfo = {
                                    zoneId: rollerInfos[i].f_zone_id,
                                    sn: rollerInfos[i].f_actuator_sn,
                                    groupIdArray: rollerInfos[i].f_actuator_group_id_array,
                                    name: rollerInfos[i].f_actuator_alias,
                                    addr: rollerInfos[i].f_actuator_addr,
                                    openChName: settings.openChName,
                                    openTravel: settings.openTravel,
                                    forceOpenTime: settings.forceOpenTime,
                                    openCorrection: settings.openCorrection,
                                    closeChName: settings.closeChName,
                                    closeTravel: settings.closeTravel,
                                    forceCloseTime: settings.forceCloseTime,
                                    closeCorrection: settings.closeCorrection,
                                    scrapTimeSec: settings.scrapTimeSec,
                                    errCorrectionNumber: settings.errCorrectionNumber,
                                    isUsedAI: settings.isUsedAI,
                                    AIChName: settings.AIChName,
                                    isForceOpen: settings.isForceOpen
                              }
                              rollersInfo.push(obj);
                        }
                  }
                  RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_ROLLERS', qryId, 'success', '查询所有卷膜设备信息成功', rollersInfo);
            } else {
                  RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_ROLLERS', qryId, 'success', '查询所有卷膜设备信息成功', rollersInfo);
            }
      }).catch((err) => {
            RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_ROLLERS', qryId, 'failure', '查询所有卷膜设备信息失败', err);
      })
}

function deleteAnyBindRollersInfoWithSn(RedisGateway: RedisGatewayClass, qryId: string, snArray: string[]) {
      let condition = `f_actuator_type="LoRa_Roller" AND f_actuator_type_id="B001" AND (f_actuator_sn='${snArray[0]}'`;
      for (let i = 1; i < snArray.length; i++) {
            condition += ` OR f_actuator_sn='${snArray[i]}'`;
      }
      condition += ')'
      console.log(condition)
      Mysql.DeletParamsFromTableWithCondition(`t_actuator`, condition).then((sta) => {
            RedisGateway.pubActuatorCmdAck('ROLLER', 'DEL_ROLLERS', qryId, 'success', '删除设备信息成功', { "snArray": snArray });
      }).catch((err) => {
            RedisGateway.pubActuatorCmdAck('ROLLER', 'DEL_ROLLERS', qryId, 'failure', '删除设备信息失败', err);
      })
}

function updateRollerInfo(RedisGateway: RedisGatewayClass, qryId: string, para: any | any[]) {
      console.log(`更新卷膜控制器信息`)
      let name = para.name;//卷膜器名
      let sn = para.sn;//区域ID
      let openChName = para.openChName;//开启通道名称
      let closeChName = para.closeChName;//关闭通道名称
      let openTravel = para.openTravel;//开启行程时间数组
      let closeTravel = para.closeTravel;//关闭行程时间数组
      let forceOpenTime = para.forceOpenTime;//强制全开时长
      let forceCloseTime = para.forceCloseTime;//强制全关时长
      let openCorrection = para.openCorrection;//开启校正偏差（每次）
      let closeCorrection = para.closeCorrection;//关闭校正偏差（每次）
      let scrapTimeSec = para.scrapTimeSec;//搭边时间
      let errCorrectionNumber = para.errCorrectionNumber;//误差校正总次数
      let isForceOpen = para.isForceOpen;//100%是否开到限位
      let isUsedAI = para.isUsedAI;
      let AIChName = para.AIChName;
      let settings = {
            "openChName": openChName,
            "openTravel": openTravel,
            "forceOpenTime": forceOpenTime,
            "openCorrection": openCorrection,
            "closeChName": closeChName,
            "closeTravel": closeTravel,
            "forceCloseTime": forceCloseTime,
            "closeCorrection": closeCorrection,
            "scrapTimeSec": scrapTimeSec,
            "errCorrectionNumber": errCorrectionNumber,
            "isForceOpen": isForceOpen,
            "isUsedAI": isUsedAI,
            "AIChName": AIChName,
            "errCorrectionCnt": 0
      }
      let f_pre_allocate3 = JSON.stringify(settings);
      let f_actuator_edit_time = moment().format('YYYY-MM-DD HH:mm:ss'); //"修改时间",
      Mysql.UpdateMultipleParamsIntoTable(`t_actuator`, ['f_actuator_alias', 'f_pre_allocate3', "f_actuator_edit_time"], [`'${name}'`, `'${f_pre_allocate3}'`, `'${f_actuator_edit_time}'`], `f_actuator_sn="${sn}"`).then(() => {
            RedisGateway.pubActuatorCmdAck('ROLLER', 'UPDATE_ROLLER', qryId, 'success', "修改卷膜设备信息成功", para);
      })
}

function Parser(RedisGateway: RedisGatewayClass, LoRaComCtrl: LoRaComCtrlClass, TcpComCtrl: TcpComCtrlClass, confTyp: string, method: string, qryId: string, para: any | any[]) {
      switch (method) {
            case "QUERY_ROLLERS":
                  queryAllRollerInfos(RedisGateway, qryId);
                  break;
            case "DEL_ROLLERS":
                  let snArray = para.snArray;
                  deleteAnyBindRollersInfoWithSn(RedisGateway, qryId, snArray);
                  break;
            case "UPDATE_ROLLER":
                  updateRollerInfo(RedisGateway, qryId, para);
                  break;
            case "QUERY_STATUS":// {"confTyp":"LORA_COMMON_CMD","method":"QUERY_STATUS","qryId":"111111111111676453731927","para":{"zoneId":1,"deviceType":"LoRa_Roller","groupId":2,"deviceSn":["B00120230215162804"]}}
                  if (para.deviceType == "LoRa_Roller") {
                        Mysql.QueryConditionalAnyDataFromTable(`t_actuator`, '*', `f_actuator_sn='${para.deviceSn[0]}' AND f_actuator_type_id='B001'`).then((params) => {
                              if (params.length > 0) {
                                    let actuatorData = {
                                          "addr": params[0].f_actuator_addr,
                                          "channel": params[0].f_channel,
                                          "status": params[0].f_actuator_status,
                                          "allocate": params[0].f_actuator_allocate,
                                          "rssi": 31,
                                          "csq": 31,
                                          "vol": 220000,
                                          "t": params[0].f_actuator_edit_time
                                    }
                                    console.log(actuatorData)
                                    RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'success', "刷新状态成功", [actuatorData]);
                              }

                        })


                  }
                  break;
            case "OPEN_SLAVER"://"sn":["B00120230207170620"],"open":[23]
                  console.log('卷膜控制')
                  let s_sn = para.sn;
                  let s_open = parseInt(para.open[0]);
                  if (s_sn.length > 1) {
                        Mysql.QueryConditionalAnyDataFromTable(`t_actuator`, '*', `f_actuator_type_id='B001'`).then((params) => {
                              let groupParams: any[] = [];
                              for (let i = 0; i < params.length; i++) {
                                    let index = s_sn.findIndex((sn) => {
                                          return sn == params[i].f_actuator_sn;
                                    })
                                    if (index != -1) {
                                          groupParams.push(params[i])
                                    }
                              }
                              if (groupParams.length > 0) {
                                    let len = groupParams.length;
                                    let addrs = new Set();
                                    let cnt = 0;
                                    groupParams.forEach(slaver => {
                                          addrs.add(slaver.f_actuator_addr);
                                    })
                                    addrs.forEach((addr) => {
                                          // console.log(addr);
                                          let mergerParams: any[] = [];
                                          for (let count = 0; count < len; count++) {
                                                let index = groupParams.findIndex((device) => {
                                                      return device.f_actuator_addr == addr;
                                                })
                                                if (index != -1) {
                                                      mergerParams.push(groupParams[index]);
                                                      groupParams.splice(index, 1);
                                                }
                                                if (count == len - 1) {
                                                      setTimeout(() => {
                                                            console.log(mergerParams)
                                                            mergeRollerGroupCtrl(RedisGateway, LoRaComCtrl, TcpComCtrl, mergerParams, s_open, false);
                                                      }, cnt * 500)
                                                }
                                          }
                                          cnt++;
                                    })
                              }
                        })
                  } else {
                        rollerOpenSlaver(RedisGateway, LoRaComCtrl, TcpComCtrl, s_sn[0], s_open, false)
                  }

                  break;
            case "FORCE_STOP"://{"zoneId":1,"groupId":2,"deviceType":"LoRa_Roller","sn":["B00120230207181500"]}
                  if (para.deviceType == "LoRa_Roller") {
                        let f_zoneId = para.zoneId;
                        let f_groupId = para.groupId;
                        let f_sn = para.sn;
                        if (f_sn[0] == '555555555555555555') {
                              Mysql.QueryConditionalDataFromTable('t_actuator_group', `f_zone_id=${f_zoneId} AND f_group_id=${f_groupId} AND f_actuator_type="LoRa_Roller"`).then((params) => {
                                    if (params.length > 0) {
                                          // console.log(params)
                                          let f_snArr = JSON.parse(params[0].f_actuator_sn_array);
                                          Mysql.QueryConditionalAnyDataFromTable(`t_actuator`, '*', `f_zone_id=${f_zoneId} AND f_actuator_type_id='B001'`).then((params1) => {
                                                if (params1.length > 0) {
                                                      let groupParams: any[] = [];
                                                      for (let i = 0; i < params1.length; i++) {
                                                            let index = f_snArr.findIndex((sn) => {
                                                                  return sn == params1[i].f_actuator_sn || sn == "555555555555555555";
                                                            })
                                                            if (index != -1) {
                                                                  groupParams.push(params1[i])
                                                            }
                                                      }
                                                      if (groupParams.length > 0) {
                                                            let len = groupParams.length;
                                                            let addrs = new Set();
                                                            let cnt = 0;
                                                            groupParams.forEach(slaver => {
                                                                  addrs.add(slaver.f_actuator_addr);
                                                            })
                                                            addrs.forEach((addr) => {
                                                                  // console.log(addr);
                                                                  let mergerParams: any[] = [];
                                                                  for (let count = 0; count < len; count++) {
                                                                        let index = groupParams.findIndex((device) => {
                                                                              return device.f_actuator_addr == addr;
                                                                        })
                                                                        if (index != -1) {
                                                                              mergerParams.push(groupParams[index]);
                                                                              groupParams.splice(index, 1);
                                                                        }
                                                                        if (count == len - 1) {
                                                                              setTimeout(() => {
                                                                                    // console.log(mergerParams)
                                                                                    mergeRollerGroupStop(RedisGateway, LoRaComCtrl, TcpComCtrl, mergerParams);
                                                                              }, cnt * 100)
                                                                        }
                                                                  }
                                                                  cnt++;
                                                            })
                                                      }
                                                }
                                          })
                                    }
                              })

                        } else {
                              Mysql.QueryConditionalAnyDataFromTable(`t_actuator`, '*', `f_actuator_type_id='B001'`).then((params) => {
                                    let groupParams: any[] = [];
                                    for (let i = 0; i < params.length; i++) {
                                          let index = f_sn.findIndex((sn) => {
                                                return sn == params[i].f_actuator_sn;
                                          })
                                          if (index != -1) {
                                                groupParams.push(params[i])
                                          }
                                    }
                                    if (groupParams.length > 0) {
                                          let len = groupParams.length;
                                          let addrs = new Set();
                                          let cnt = 0;
                                          groupParams.forEach(slaver => {
                                                addrs.add(slaver.f_actuator_addr);
                                          })
                                          addrs.forEach((addr) => {
                                                // console.log(addr);
                                                let mergerParams: any[] = [];
                                                for (let count = 0; count < len; count++) {
                                                      let index = groupParams.findIndex((device) => {
                                                            return device.f_actuator_addr == addr;
                                                      })
                                                      if (index != -1) {
                                                            mergerParams.push(groupParams[index]);
                                                            groupParams.splice(index, 1);
                                                      }
                                                      if (count == len - 1) {
                                                            setTimeout(() => {
                                                                  // console.log(mergerParams)
                                                                  mergeRollerGroupStop(RedisGateway, LoRaComCtrl, TcpComCtrl, mergerParams);
                                                            }, cnt * 500)
                                                      }
                                                }
                                                cnt++;
                                          })
                                    }
                              })
                        }


                  }

                  break;
            case "OPEN_GROUP"://{"zoneId":1,"groupId":[2],"open":[0]}}
                  let g_zoneId = para.zoneId;
                  let g_groupId = para.groupId[0];
                  let g_open = parseInt(para.open[0]);
                  let g_sn = para.sn == undefined ? ["555555555555555555"] : para.sn;
                  console.log(g_sn)
                  if (g_sn[0] == '555555555555555555') {
                        Mysql.QueryConditionalDataFromTable('t_actuator_group', `f_zone_id=${g_zoneId} AND f_group_id=${g_groupId} AND f_actuator_type="LoRa_Roller"`).then((params) => {
                              if (params.length > 0) {
                                    let g_snArr = JSON.parse(params[0].f_actuator_sn_array);
                                    console.log(g_snArr)
                                    Mysql.QueryConditionalAnyDataFromTable(`t_actuator`, '*', `f_zone_id=${g_zoneId} AND f_actuator_type_id='B001'`).then((params1) => {
                                          if (params1.length > 0) {
                                                let groupParams: any[] = [];
                                                for (let i = 0; i < params1.length; i++) {
                                                      let index = g_snArr.findIndex((sn) => {
                                                            return sn == params1[i].f_actuator_sn || sn == "555555555555555555";
                                                      })
                                                      if (index != -1) {
                                                            groupParams.push(params1[i])
                                                      }
                                                }
                                                if (groupParams.length > 0) {
                                                      let len = groupParams.length;
                                                      let addrs = new Set();
                                                      let cnt = 0;
                                                      groupParams.forEach(slaver => {
                                                            addrs.add(slaver.f_actuator_addr);
                                                      })
                                                      addrs.forEach((addr) => {
                                                            // console.log(addr);
                                                            let mergerParams: any[] = [];
                                                            for (let count = 0; count < len; count++) {
                                                                  let index = groupParams.findIndex((device) => {
                                                                        return device.f_actuator_addr == addr;
                                                                  })
                                                                  if (index != -1) {
                                                                        mergerParams.push(groupParams[index]);
                                                                        groupParams.splice(index, 1);
                                                                  }
                                                                  if (count == len - 1) {
                                                                        setTimeout(() => {
                                                                              // console.log(mergerParams)
                                                                              mergeRollerGroupCtrl(RedisGateway, LoRaComCtrl, TcpComCtrl, mergerParams, g_open, false);
                                                                        }, cnt * 500)
                                                                  }
                                                            }
                                                            cnt++;
                                                      })
                                                }
                                          }
                                    })


                              }
                        })
                  } else {
                        Mysql.QueryConditionalAnyDataFromTable(`t_actuator`, '*', `f_actuator_type_id='B001'`).then((params) => {
                              let groupParams: any[] = [];
                              for (let i = 0; i < params.length; i++) {
                                    let index = g_sn.findIndex((sn) => {
                                          return sn == params[i].f_actuator_sn;
                                    })
                                    if (index != -1) {
                                          groupParams.push(params[i])
                                    }
                              }
                              if (groupParams.length > 0) {
                                    let len = groupParams.length;
                                    let addrs = new Set();
                                    let cnt = 0;
                                    groupParams.forEach(slaver => {
                                          addrs.add(slaver.f_actuator_addr);
                                    })
                                    addrs.forEach((addr) => {
                                          // console.log(addr);
                                          let mergerParams: any[] = [];
                                          for (let count = 0; count < len; count++) {
                                                let index = groupParams.findIndex((device) => {
                                                      return device.f_actuator_addr == addr;
                                                })
                                                if (index != -1) {
                                                      mergerParams.push(groupParams[index]);
                                                      groupParams.splice(index, 1);
                                                }
                                                if (count == len - 1) {
                                                      setTimeout(() => {
                                                            // console.log(mergerParams)
                                                            mergeRollerGroupCtrl(RedisGateway, LoRaComCtrl, TcpComCtrl, mergerParams, g_open, false);
                                                      }, cnt * 500)
                                                }
                                          }
                                          cnt++;
                                    })
                              }
                        })
                  }

                  break;
            default:
                  break;
      }
}

export = {
      Parser,
      calculateOpenTravelTime,
      calculateCloseTravelTime
}